home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
hardware
/
2m30src
/
2mgui.asm
< prev
next >
Wrap
Assembly Source File
|
1995-03-06
|
269KB
|
6,550 lines
;┌───────────────────────────────────────────────────────────────────┐
;│ │
;│ █████ █ █ █████ █ █ █████ │
;│ █ ██ ██ █ █ █ █ │
;│ █████ █ █ █ █ ███ █ █ █ │
;│ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █████ █████ █████ V 1.0 │
;│ │
;│ │
;│ CODIGO PARA CREAR Y CONTROLAR DISQUETES │
;│ APROVECHANDO LA CAPACIDAD ANTES DE FORMATEAR │
;│ EN SISTEMAS PC, XT, AT - ISA/EISA/VLB/PCI (No MCA) │
;│ CON CONTROLADORAS Y UNIDADES DE ALTA DENSIDAD │
;│ │
;│ (C) 1994-1995 Ciriaco García de Celis. │
;│ Email: ciri@gui.uva.es │
;│ FidoNET 2:341/21.8 │
;│ Grupo Universitario de Informática │
;│ Facultad de Ciencias - Valladolid (España) │
;│ │
;│ Ensamblar con TASM 2mgui /m5 y enlazar con TLINK 2mgui │
;│ Se necesita el fichero 2MUTIL.INC incluído en 2M 3.0 │
;│ │
;└───────────────────────────────────────────────────────────────────┘
; ------------ Constantes fundamentales y valores por defecto.
M_DMA EQU ON ; modo DMA por defecto
FRONT EQU 28 ; pista de división del disco 360DH
GAPDEF EQU 20 ; GAP anti-FIFO por defecto
MODOWR EQU ON ; por defecto, caché de escritura
W_CACHE_TM EQU 9 ; escritura retardada: 9/18 segundos
PRE_GAP3 EQU 20 ; GAP3 para preformateo
MPISTA EQU 30000 ; mayor pista absoluta posible
PISTAS EQU 82 ; nº pistas por defecto
SECTDEF EQU 128 ; tamaño de sector lógico por defecto
CLUSDEF EQU 1024 ; tamaño de clúster por defecto
MINROOT EQU 128 ; entradas raíz mínimo por defecto
SLID_X EQU 55 ; sliding X por defecto (en grados)
SLID_Y EQU 90 ; sliding Y por defecto (en grados)
t_525_dd EQU 6098 ; tamaños recomendados (t_)
m_525_dd EQU 6250 ; y límites teóricos por pista (m_)
t_525_hd EQU 10239
m_525_hd EQU 10416
t_35_dd EQU 7343
m_35_dd EQU 7500
t_35_hd EQU 12313
m_35_hd EQU 12500
t_35_ed EQU 24626
m_35_ed EQU 25000
; ------------ Macros de propósito general.
XPUSH MACRO regmem ; apilar lista de registros
IRP rm, <regmem>
PUSH rm
ENDM
ENDM
XPOP MACRO regmem ; desapilar lista de registros
IRP rm, <regmem>
POP rm
ENDM
ENDM
XPUSHA MACRO
XPUSH <AX, BX, CX, DX, SI, DI, BP>
ENDM
XPOPA MACRO
XPOP <BP, DI, SI, DX, CX, BX, AX>
ENDM
DDS MACRO
PUSH AX
MOV AX,40h
MOV DS,AX
POP AX
ENDM
DELAY MACRO ; estados de espera
JMP SHORT $+2 ; para AT obsoleto
JMP SHORT $+2
ENDM
PMICRO MACRO ; retardo de aprox. 15,09 µs
LOCAL pmicro_iter ; (exactamente 18/1193180 sg.)
pmicro_iter: DELAY
IN AL,61h ; Esta macro puede ejecutarse
AND AL,10h ; repetitivamente (se apoya en
CMP AL,AH ; AX) para hacer retardos a
JE pmicro_iter ; través de la temporización
MOV AH,AL ; del refresco de la memoria
ENDM ; dinámica de los AT.
; ------------ Estructuras de datos.
cab_PETICION STRUC ; parte inicial común a todos
tamano DB ? ; los comandos de la cabecera
unidad_disco DB ? ; de petición
orden_dsp DB ?
estado DW ?
dos_info DB 8 DUP (?)
cab_PETICION ENDS
cab_INIT_BBPB STRUC ; para comandos INIT/BUILD_BPB
DB (TYPE cab_PETICION) DUP (?)
num_disc_init DB ? ; número de unidades definidas
fin_resid_desp DW ? ; área que quedará residente
fin_resid_segm DW ?
bpb_cmd EQU THIS DWORD
bpb_cmd_desp DW ? ; línea de órdenes del CONFIG
bpb_cmd_segm DW ? ; y puntero al BPB
nuevo_disco DB ? ; (DOS 3+) (0-A:, 1-B:,...)
cab_INIT_BBPB ENDS
cab_MEDIACHECK STRUC ; estructura para MEDIA CHECK
DB (TYPE cab_PETICION) DUP (?)
media_descrip DB ? ; descriptor de medio
cambio DB ? ; 1: no cambiado, 0FFh:sí, 0:?
cab_MEDIACHECK ENDS
cab_READ_WRITE STRUC
DB (TYPE cab_PETICION) DUP (?)
DB ? ; descriptor de medio
transfer_desp DW ? ; dirección de transferencia
transfer_segm DW ?
transfer_sect DW ? ; nº de sectores a transferir
transfer_sini DW ? ; primer sector a transferir
cab_READ_WRITE ENDS
cab_GEN_IOCTL STRUC
DB (TYPE cab_PETICION) DUP (?)
categoria_cod DB ? ; código de categoría
func_cod DB ? ; código de función
copia_ds DW ?
offset_cab DW ?
ioctl_info DD ? ; puntero a información
cab_GEN_IOCTL ENDS
; --- Estructura con información local a la unidad.
; Contiene información IOCTL, el BPB y otras.
InfoBoot STRUC ; subestructura auxiliar
vformat DW 0100h ; versión 1.0
fformat DW 0 ; sin flags especiales en esta versión
vunidad2 DB ? ; densidad segunda parte del disco
mfrontera DB ? ; frontera divisora
tpista1 DW ? ; tamaño físico pistas 0..FRONTERA-1
tpista2 DW ? ; tamaño físico pistas FRONTERA..81
idboot DW 0AA55h ; ID de sector válido
InfoBoot ENDS
info_unidad STRUC
DB ? ; "sectores iguales" o no
DB ? ; tipo (1-1.2, 7-1.44, 9-2.88)
DW ? ; detección de cambio
ioctl_pistas DW ? ; nº pistas
ioctl_id DB '2'+'M' ; tipo de soporte
bytes_sector DW ? ; BPB: bytes por sector
sect_cluster DB ? ; BPB: sectores por cluster
sect_reserv DW ? ; BPB: sectores reservados
num_fats DB ? ; BPB: número de FATs
entradas_raiz DW ? ; BPB: entradas en el raíz
num_sect DW ? ; BPB: nº total de sectores
media_byte DB ? ; BPB: descriptor de medio
sectores_fat DW ? ; BPB: sectores por FAT
sectores_pista DW ? ; BPB: sectores por pista
num_cabezas DW ? ; BPB: cabezas
sects_ocultos DD ? ; BPB: sectores ocultos
DD 0 ; BPB: sectores (32bit)
DB 11 DUP (0) ; BPB: restantes campos
unidad DB ? ; unidad física
tipo_drv DB 0 ; tipo de la disquetera (0 = no hay)
modobios DB ON ; a ON si el disquete no es 2MGUI
controldrv DB OFF ; a ON si el disco lo controla 2MGUI
cambiodisco DB ON ; a ON por defecto para simular cambio
cilindro DB ? ; cilindro del disco a acceder
cabezal DB ? ; cabezal a emplear
vunidad1 DB ? ; # velocidad primer medio disco
infb InfoBoot <> ; información del BOOT
tsector DB ? ; # LOG2 (tamaño buffer) redondeado
prot_esc DB ? ; ON = disco protegido contra escritura
numserie DD 12345678h ; número de serie del disco
evol DB "NO NAME " ; etiqueta de volúmen (BOOT)
fsystem DB "FAT12 " ; sistema de ficheros
info_unidad ENDS
; ------------ Códigos de modos y órdenes del DMA, FDC,...
BIOS_READ EQU 2
BIOS_WRITE EQU 3
F_READ EQU 46h ; modo DMA para lectura
F_WRITE EQU 4Ah ; modo DMA para escritura
F_VERIFY EQU 42h ; modo DMA para verificación
F_FORMAT EQU 01001101b ; orden de formateo del FDC
TICSTIMEOUT EQU 9322 ; constante para 2 segundos
FD_STATUS EQU 3F4h ; registro de estado
FD_DOR EQU 3F2h ; registro de salida digital
FD_DIR EQU 3F7h ; registro de entrada digital
FD_DCR EQU 3F7h ; registro de control disco
; ************ Inicio del área residente.
_PRINCIPAL SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
ORG 0
ini_residente EQU $
DD -1 ; encadenamiento con otros drivers
tipo_drive DW 2840h ; palabra de atributo:
; bit 15 a 0: dispositivo de bloques
; bit 14 a 0: sin control IOCTL
; bit 13 a 1: SIN formato IBM
; bit 11 a 1: Open/Close/Remove
; bit 6 a 1: Generic Ioctl
DW estrategia ; rutina de estrategia
DW interrupcion ; rutina de interrupción
num_discos DB 255 ; número de unidades (255 antes
; de que INIT lo inicialice)
; ***************************************************
; * *
; * D A T O S D E L C O N T R O L A D O R *
; * *
; ***************************************************
; ------------ Identificación estandarizada del programa.
program_id LABEL BYTE
segmento_real DW 0 ; segmento real donde será cargado
offset_real DW 0 ; offset real " " "
longitud_total DW 0 ; zona de memoria ocupada (párrafos)
info_extra DB 03h ; bits 0, 1 y 2-> 000: normal, con PSP
; 001: bloque UMB XMS
; 010: *.SYS
; 011: *.SYS formato EXE
; bit 7 a 1: «extension_id» definida
multiplex_id DB 0 ; número Multiplex de este TSR
vectores_id DW tabla_vectores
extension_id DW 0
DB "*##*"
autor_nom_ver DB "CiriSOFT:2MGUI:1.0",0
DB 3 ; número de vectores de interrupción usados
tabla_vectores EQU $
DB 8h ; INT 8h
ant_int08 LABEL DWORD ; dirección original
ant_int08_off DW 0
ant_int08_seg DW 0
DB 13h ; INT 13h
ant_int13 LABEL DWORD ; dirección original
ant_int13_off DW 0
ant_int13_seg DW 0
DB 2Fh ; INT 2Fh
ant_int2F LABEL DWORD ; dirección original
ant_int2F_off DW 0
ant_int2F_seg DW 0
; ------------ Datos de trabajo.
pcab_peticion LABEL DWORD ; puntero a la cabecera de petición
pcab_pet_desp DW 0
pcab_pet_segm DW 0
p_rutinas LABEL WORD ; tabla de rutinas del controlador
DW init
DW media_check
DW build_bpb
DW nofunc
DW read
DW read_nowait
DW input_status
DW input_flush
DW write
DW write_verify
DW output_status
DW output_flush
DW ioctl_output
DW open ; DOS 3.0+
DW close ; DOS 3.0+
DW remove ; DOS 3.0+
DW nofunc
DW nofunc
DW nofunc
DW generic_ioctl ; DOS 3.2+
drv_pvars LABEL WORD ; punteros a variables y BPB
DW info_E
DW info_F
bpb_ptrs LABEL WORD ; tabla de punteros BPB
DW info_E.bytes_sector
DW info_F.bytes_sector
info_E info_unidad <> ; 2 BPB's para las 2 unidades
info_F info_unidad <> ; posibles ya inicializados y
; sus variables particulares.
info_BUF info_unidad <> ; para la pista en el buffer
pet_fantasma cab_READ_WRITE <> ; cabecera de petición de
; solicitud fantasma
; ----- Variables de control globales.
unidad_base DB ? ; primera letra de unidad definida
tbase DW ? ; constante para retardos (XT)
pcxt DB OFF ; a ON si no es AT
drdos6 DB OFF ; a ON si es DR-DOS 6.0 ó Novell DOS 7.0
tbuffer DW ? ; tamaño del buffer interno en bytes
sbuffer DW ? ; puntero al segmento del buffer
sbuf512 DW ? ; copia de seguridad del mismo
ems_handle DW 0 ; handle EMS (si usado)
marco_ems DW ? ; marco de página EMS (si usado)
ems4 DB OFF ; a ON en EMS 4.0+
SYSBYTES EQU 2 ; en cada pista, NOT(checksum) (2 bytes)
gaprw DW GAPDEF ; GAP R/W simulado
cachewr DB MODOWR ; modo para la caché de escritura
modoDMA DB M_DMA ; modo DMA activo por defecto
sentidoIO DB ? ; F_WRITE ó F_READ según operación NO-DMA
bytesIO DW ? ; bytes para operación NO-DMA
sector_ini DB ? ; número de sector inicial en los accesos
sector_fin DB ? ; número de sector final en los accesos
off_ini DW ? ; # offset inicial en la pista
off_fin DW ? ; # offset final en la pista + 1
bytes DW ? ; # bytes a transferir
wrpend DB OFF ; a ON si pista en buffer aún no escrita
expiraw DB ? ; contador de tics escritura retardada
orden DB ? ; operación READ/WRITE
verificar DB OFF ; a ON si WRITE VERIFY
status DB ? ; resultado de los accesos a disco
fdc_result DB 7 DUP (?) ; bytes de resultados del FDC
; --- Interpretación BIOS de los bits de ST1
lista_errs DB 4 ; 'sector not found'
DB 0
DB 10h ; 'bad CRC'
DB 8 ; 'DMA overrun'
DB 0
DB 4 ; 'sector not found'
DB 3 ; 'write-protect error'
DB 2 ; 'address mark not found'
DB 20h ; en otro caso: 'bad NEC'
; *****************************************************
; * *
; * C O D I G O D E L C O N T R O L A D O R *
; * *
; *****************************************************
; ------------ Rutina de gestión de INT 2Fh.
; También se impide que SMARTDRIVE 4.0+ cachee por
; defecto las nuevas unidades (se cuelga al acceder si
; los sectores no son de 512 bytes).
ges_int2F PROC FAR
STI
PUSH CX ; *
CMP AX,4A10h
JNE i2f_tsr ; no llama smartdrive
CMP BX,6
JNE i2f_tsr ; no llama smartdrive
SUB CL,CS:unidad_base
DEC CL
JZ no_gracias ; llama smartdrive
CMP CS:info_F.unidad,0
JE i2f_tsr ; no llama para nuestra unidad
DEC CL
JNZ i2f_tsr ; no llama para nuestra unidad
no_gracias: POP CX ; *1
MOV AX,6 ; nos llama: "No, gracias"
RETF 2
i2f_tsr: POP CX ; *2
CMP AH,CS:multiplex_id
JE preguntan
JMP CS:ant_int2F ; saltar al gestor de INT 2Fh
preguntan: CMP DI,1992h
JNE ret_no_info ; no llama alguien del convenio
MOV AX,ES
CMP AX,1492h
JNE ret_no_info ; no llama alguien del convenio
PUSH CS
POP ES ; sí llama: darle información
LEA DI,autor_nom_ver
ret_no_info: MOV AX,0FFFFh ; "entrada multiplex en uso"
IRET
ges_int2F ENDP
; ------------ Rutina de gestión de INT 8. Se utiliza para grabar
; en disco el buffer con la pista pendiente de ser
; grabada (caché de escritura retardada) si pasa
; demasiado tiempo tras el último acceso.
ges_int08 PROC FAR
CLI ; por si llamada con CALL/JMP
CMP CS:wrpend,OFF
JE bye08
DEC CS:expiraw
JNZ bye08
XPUSHA ; *
XPUSH <DS, ES> ; **
XPUSH <CS, CS>
XPOP <DS, ES>
MOV AL,20h
OUT 20h,AL ; para que funcione IRQ6 ;-)
CALL abs_flush
XPOP <ES, DS> ; **
XPOPA ; *
bye08: JMP CS:ant_int08
ges_int08 ENDP
; ------------ Rutina de gestión de INT 13h. Se utiliza para simular
; cambios de disco tanto en las nuevas unidades como en
; las normales, cuando el usuario conmuta entre ambas,
; ya que el primer acceso desde una de ellas baja la
; línea de cambio y ésta es la única manera de asegurar
; que la información del disco se corresponde con éste
; y no con otro antiguo ya sustituído.
ges_int13 PROC FAR
STI
CMP DL,2
JB ges_swp
bios13: JMP CS:ant_int13
ges_swp: CMP AH,2
JB bios13
CMP AH,16h
JE simcamb?
CMP AH,5
JA bios13
simcamb?: PUSH BX
LEA BX,info_E ; apuntar datos unidad
CMP CS:[BX].unidad,DL
JE tab_dat_ok
LEA BX,info_F
CMP CS:[BX].unidad,DL
JE tab_dat_ok
POP BX
JMP bios13
tab_dat_ok: CMP CS:[BX].controldrv,ON
MOV CS:[BX].controldrv,OFF ; simular cambio de disco
MOV CS:[BX].cambiodisco,ON ; en nueva unidad
POP BX
JNE bios13
STC
MOV AH,6
RET 2 ; y en la A: ó B:
ges_int13 ENDP
; ------------ Rutina de estrategia.
estrategia PROC FAR
MOV CS:pcab_pet_desp,BX
MOV CS:pcab_pet_segm,ES
RET
estrategia ENDP
; ------------ Rutina de interrupción.
interrupcion PROC FAR
STI
XPUSHA
XPUSH <DS, ES>
LDS BX,CS:pcab_peticion
MOV AL,[BX].orden_dsp ; AL = orden
MOV AH,0 ; AX = orden
CMP AL,13h
JBE orden_ok ; orden soportada
MOV AX,8103h ; orden desconocida
JMP exit_interr
orden_ok: SHL AX,1 ; orden = orden * 2
MOV DI,AX
ADD DI,OFFSET p_rutinas
LEA SI,drv_pvars
MOV AL,[BX].unidad_disco
CMP AL,CS:num_discos
JB disco_ok
MOV AX,8101h ; unidad desconocida
JMP exit_interr
disco_ok: MOV AH,0
SHL AX,1
ADD SI,AX
MOV SI,CS:[SI] ; SI -> BPB y juego variables
XPUSH <BX,DS>
CALL CS:[DI] ; ejecutar orden
XPOP <DS,BX>
exit_interr: MOV [BX].estado,AX
XPOP <ES, DS>
XPOPA
RET
interrupcion ENDP
; ------------ Las rutinas que controlan el dispositivo devuelven AX
; con la palabra de estado. Pueden cambiar todos los
; registros, incluídos los de segmento. A la entrada,
; DS:BX apunta a la cabecera de petición de solicitud y
; CS:SI al BPB y las variables de la unidad invocada.
read_nowait: ; órdenes ignoradas...
input_status:
input_flush:
output_status:
output_flush:
ioctl_output:
open:
close:
remove: ; dispositivo removible
retorno_ok: MOV AX,100h
RET
nofunc: MOV AX,8103h ; orden no soportada
RET
; --- Soporte IOCTL.
; - Implementa las funciones:
; 60h - Obtener parámetros del dispositivo
; 66h - Devolver nº de serie (para el DIR)
; 41h - Escritura de pista (para DISKCOPY)
; 61h - Lectura de pista (para DISKCOPY)
; - Ignora las funciones:
; 40h - Establecer parámetros del dispositivo
; 46h - Establecer nº de serie
; - Indica siempre que no está permitido:
; 42h - Formatear y verificar pista
; 62h - Verificar pista
; - Retorna error de "no soportado" en las demás
generic_ioctl: LDS BX,CS:pcab_peticion
CMP [BX].categoria_cod,8
JNE gen_ioctl_rtf
MOV AL,[BX].func_cod
CMP AL,60h ; soportado subcódigo 60h
JE get_devp
CMP AL,66h ; 66h
JE get_serie
CMP AL,46h ; 46h
JE set_serie
CMP AL,40h ; 40h
JE set_devp
CMP AL,41h ; 41h
JE wr_ioctl
CMP AL,61h ; y 61h
JE rd_ioctl
CMP AL,42h
JE ioct_nosup
CMP AL,62h
JE ioct_nosup
gen_ioctl_rtf: MOV AX,8103h ; orden no soportada
RET
get_devp: LES DI,[BX].ioctl_info ; orden 0860h invocada
TEST BYTE PTR ES:[DI],1
JZ devp ; no acceder a disco
XPUSHA
XPUSH <DS, ES>
CALL build_bpb ; actualizar datos
XPOP <ES, DS>
XPOPA
devp: INC SI
INC DI
MOV CX,38
PUSH CS
POP DS
CLD
REP MOVSB
set_devp: JMP gen_ioctl_ret ; subcódigo 40h ignorado
get_serie: LES DI,[BX].ioctl_info
ADD DI,2
PUSH CS
POP DS
LEA SI,[SI].numserie
MOV CX,23
CLD
REP MOVSB ; devolver nº serie y demás
set_serie: JMP gen_ioctl_ret ; no implementado cambiarlo
ioct_nosup: LES DI,[BX].ioctl_info
MOV BYTE PTR ES:[DI],2
MOV AX,8107h ; no soportado format/verify
RET
gen_ioctl_ret: MOV AX,100h ; Ok
RET
wr_ioctl: CALL ioctl_io_info
AND AX,AX
JNZ noserie
MOV AX,ES:[DI+39] ; actualizar número de
MOV CX,ES:[DI+41] ; serie en memoria
LEA DI,[SI].numserie
MOV CS:[DI],AX
MOV CS:[DI+2],CX
noserie: CALL io_drdos
CALL write
RET
rd_ioctl: CALL ioctl_io_info
CALL io_drdos
CALL read
RET
ioctl_io_info: LES DI,[BX].ioctl_info
MOV AX,ES:[DI+3] ; cilindro
MUL CS:[SI].num_cabezas
ADD AX,ES:[DI+1] ; cabezal
MUL CS:[SI].sectores_pista
ADD AX,ES:[DI+5] ; AX = sector inicial
MOV CX,ES:[DI+7] ; CX = número sectores
LES DI,ES:[DI+9] ; ES:DI = dirección E/S
PUSH CS
POP DS
LEA BX,pet_fantasma
MOV [BX].transfer_desp,DI
MOV [BX].transfer_segm,ES
MOV [BX].transfer_sect,CX ; nº sectores
MOV [BX].transfer_sini,AX ; primer sector
RET
; --- El diskcopy de DR-DOS 6.0+ empieza a copiar
; por el final, descendentemente. Para evitar la
; inevitable recalibración en cada pista al tener
; que ir una pista atrás, se copia al revés ;-)
io_drdos PROC
CMP drdos6,ON
JNE io_dr_ok
CMP [SI].sectores_pista,1
JNE io_dr_ok ; no es un disco 2MGUI
MOV AX,[SI].num_sect
SUB AX,[BX].transfer_sini
SUB AX,[BX].transfer_sect
MOV [BX].transfer_sini,AX ; sector opuesto
io_dr_ok: RET
io_drdos ENDP
; ------------ Rutina de detección de cambio de disco.
media_check: CMP CS:[SI].cambiodisco,ON
MOV CS:[SI].cambiodisco,OFF
MOV CS:[SI].controldrv,ON
MOV AL,0FFh ; supuesto cambio de disco
JE set_cambio ; disco recién formateado
MOV DL,CS:[SI].unidad
CALL leer_lin_camb ; en 1.2M/1.44M/2.88M...
JNZ set_cambio
MOV AL,1 ; sin cambio de disco
set_cambio: MOV [BX].cambio,AL
MOV AX,100h
RET
; ------------ Devolver ZF=1 si la línea de cambio de disco está
; inactiva. A la entrada, DL contiene la unidad. El
; motor es puesto en marcha y, si no lo estaba ya, la
; variable que indica lo que resta para detenerlo
; es llevada a su valor normal, por lo que el disco no
; tardará mucho en detenerse (incluso sin quizá haber
; acelerado aún).
leer_lin_camb PROC
XPUSHA ; *
PUSH DS
DDS
MOV AL,1
MOV CL,DL
SHL AL,CL ; bit de motor en 0..3
TEST DS:[3Fh],AL
JNZ rodando ; el motor ya está girando
CLC
CALL motor_off_cnt ; cuenta normal detención motor
rodando: MOV AH,DL
MOV CL,4
SHL AH,CL
OR AH,AL ; AH = byte BIOS
SHL AL,CL
OR AL,00001100b ; modo DMA, no hacer reset
OR AL,DL ; AL para reg. salida digital
MOV DX,FD_DOR
CLI
MOV DS:[3Fh],AH ; actualizar variable BIOS
OUT DX,AL ; arrancado motor en la unidad
ADD DX,5
DELAY
IN AL,DX ; leer línea de cambio de disco
STI
TEST AL,80h ; ZF=0 -> cambio de disco
POP DS
XPOPA ; *
RET
leer_lin_camb ENDP
; ------------ Como el disco no es de tipo IBM, el DOS no intentará
; leer el primer sector de la FAT después de invocar
; media_check y antes de invocar build_bpb.
build_bpb: XPUSH <CS, CS>
XPOP <DS, ES>
CALL abs_flush ; liquidar escritura pendiente
det_media: MOV [SI].cilindro,0
MOV [SI].cabezal,0
MOV [SI].vunidad1,0
MOV [SI].infb.vunidad2,0
STC
CALL reset_drv
CALL motor_ok
CALL seek_drv
MOV [SI].tsector,7 ; todo menos 2.88M
MOV CX,2
intenta_2mg: CLC
CALL reset_drv
XOR DX,DX ; empezar por alta densidad
densidad_2mg?: MOV [SI].vunidad1,DL
MOV [SI].infb.vunidad2,DH
CALL detect_2mgui
JE detectado_2mg
TEST status,80h
JNZ proc_bios ; ¿unidad no preparada?
ADD DX,0101h
CMP DL,3
JBE densidad_2mg? ; buscar densidad
LOOP intenta_2mg
JMP proc_bios
detectado_2mg: XPUSH <AX, BX, DI> ; *
MOV [SI].prot_esc,OFF ; supuesto no protegida...
CALL test_st3
JNC baja_lc
MOV [SI].prot_esc,ON ; protegida contra escritura
baja_lc: MOV [SI].cilindro,1
CALL seek_drv
MOV [SI].cilindro,0
CALL seek_drv ; bajar línea cambio de disco
MOV DX,FD_DIR
IN AL,DX ; leer línea de cambio de disco
MOV AH,80h
TEST AL,AH ; ZF=0 -> cambio de disco
XPOP <DI, BX, AX> ; *
JNZ no_listo
JMP s0_2mg_ok
proc_bios: MOV CX,3
intenta_bios: CALL detect_bios ; intentar acceso BIOS
JNC s0_bios_ok
LOOP intenta_bios
no_listo: CMP AH,80h
JE proc_err ; unidad no preparada
CLC
CALL reset_drv
CALL motor_ok
CALL seek_drv
MOV [SI].tsector,8 ; ¿será 2.88M?
MOV CX,2
intenta_2mg28: MOV DX,0303h ; sólo extraalta densidad
MOV [SI].vunidad1,DL
MOV [SI].infb.vunidad2,DH
CALL detect_2mgui
JE detectado_2mg
LOOP intenta_2mg28
MOV AL,20h ; indicar 'anomalía general'
proc_err: CALL errbios2dos
MOV [SI].modobios,ON ; disco no-2MGUI
RET
s0_2mg_ok: MOV [SI].modobios,OFF ; disco 2MGUI
MOV AL,7 ; log2 (16384) - 7 = 7
CMP [SI].infb.tpista1,16384
JBE tsec_ok
INC AL ; log2 (32768) - 7 = 8
tsec_ok: MOV [SI].tsector,AL
MOV DS,sbuffer
MOV BX,11
JMP s0_dos
s0_bios_ok: MOV [SI].modobios,ON ; disco no-2MGUI
MOV DS,sbuffer
MOV BX,11 ; offset en BOOT para el BPB
CMP WORD PTR [BX],512 ; ¿sectores de 512?
JE s0_dos
MOV AX,8107h ; 'medio físico desconocido'
RET
s0_dos: PUSH SI ; *
LEA DI,[SI].bytes_sector
LEA SI,[SI].numserie
XCHG SI,BX ; SI -> BPB del sector
MOV CX,17
XPUSH <SI, DI>
CLD
REP MOVSB ; construir BPB...
XPOP <DI, SI>
PUSH DI
MOV DI,BX
ADD SI,28 ; apuntar al nº serie y demás
MOV CX,23
REP MOVSB ; anotarlo
POP DI
POP SI ; *
MOV AX,ES:[SI].sectores_pista
MUL ES:[SI].num_cabezas
MOV CX,AX
MOV AX,ES:[SI].num_sect
XOR DX,DX
DIV CX
MOV ES:[SI].ioctl_pistas,AX
LDS BX,CS:pcab_peticion
MOV [BX].bpb_cmd_desp,DI ; nuevo BPB obtenido
MOV [BX].bpb_cmd_segm,CS
MOV AX,100h ; Ok.
RET
; --- Detectar un disco 2MGUI y devolver AX=tpista1
; y BX=tpista2
detect_2mgui: XPUSH <CX, DX>
MOV info_BUF.unidad,-1
MOV [SI].cilindro,0
MOV [SI].cabezal,0
MOV AX,sbuf512
MOV sbuffer,AX ; no usar EMS para esto
MOV [SI].infb.tpista1,512 ; con 512 bytes basta
MOV [SI].infb.mfrontera,86
PUSH ES ; *
MOV ES,sbuffer
MOV ES:[PINFOBOOT].idboot,0
POP ES ; *
CLC
CALL reset_drv
CALL motor_ok
CALL seek_drv
CALL lee_pista
CALL anotar_acceso
XPUSH <DS, ES, SI> ; **
PUSH DS
POP ES
MOV DS,sbuffer
LEA DI,[SI].infb
MOV SI,PINFOBOOT
MOV CX,(TYPE InfoBoot) - 2 ; respetar marca 0xAA55
CLD
REP MOVSB ; anotar información física BOOT
CMP WORD PTR DS:[PINFOBOOT].idboot,0AA55h ; ¿2MGUI?
XPOP <SI, ES, DS> ; **
XPOP <DX, CX> ; *
RET
; --- Detectar un disco estándar.
detect_bios: PUSH CX ; *
MOV AH,0
MOV DL,[SI].unidad
PUSHF
CALL CS:ant_int13 ; reset de disco
media_detect: MOV info_BUF.unidad,-1 ; invalidar buffer
PUSH ES ; **
MOV ES,sbuffer
XOR BX,BX
MOV DL,[SI].unidad
MOV DH,0
MOV CX,1
MOV AX,201h
PUSHF
CALL CS:ant_int13 ; leer sector de arranque
POP ES ; **
POP CX ; *
RET
; --- Comprobar ST3 para saber si el disco está
; protegido contra escritura.
test_st3 PROC
PUSH AX
MOV AL,4 ; comando para leer ST3
CALL fdc_write
JC st3_ok
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL fdc_write ; enviar HD, US1, US0
JC st3_ok
CALL fdc_read
JC st3_ok
TEST AL,64 ; ¿protegido contra escritura?
JZ st3_ok
POP AX
STC
RET
st3_ok: POP AX
CLC
RET
test_st3 ENDP
; ------------ Realizar lecturas y escrituras.
read: MOV CS:verificar,OFF
MOV CS:orden,BIOS_READ
JMP prepara_io
write_verify: MOV CS:verificar,ON
MOV CS:orden,BIOS_WRITE
JMP prepara_io
write: MOV CS:verificar,OFF
MOV CS:orden,BIOS_WRITE
prepara_io PROC
LES DI,DWORD PTR [BX].transfer_desp ; dirección
MOV CX,[BX].transfer_sect ; nº sectores
MOV BX,[BX].transfer_sini ; primer sector
PUSH CS
POP DS
ADD BX,CX
JNC io_ok? ; último sector < 65536
io_no_ok: MOV AX,8108h ; error 'sector no encontrado'
RET
io_ok?: CMP BX,[SI].num_sect
JA io_no_ok ; sector final ¡fuera!
SUB BX,CX ; BX = primer sector
prepara_io ENDP
CMP [SI].modobios,ON
JE calcula_dir ; disco soportado por la BIOS
CMP ems_handle,0 ; disco soportado por 2MGUI
JNE acc_ems
JMP rwv2mgui ; no usada memoria EMS
acc_ems: MOV DX,ems_handle ; usada memoria EMS
MOV AH,47h
XPUSH <BX, CX, SI, DI>
INT 67h ; preservar el contexto
XPOP <DI, SI, CX, BX>
CMP AH,82h
JE acc_ems ; reintentar
AND AH,AH
MOV AX,810Ch ; fallo: anomalía general
JNZ rt_acc
CALL rwv2mgui
PUSH AX
rrst: MOV DX,CS:ems_handle ; ¡DS corrompido si error!
MOV AH,48h
INT 67h ; restaurar el contexto
CMP AH,82h
JE rrst ; reintentar; si falla, pasar
POP AX
rt_acc: RET
calcula_dir PROC
MOV AX,[SI].sectores_pista
MUL [SI].num_cabezas
XCHG AX,BX
XOR DX,DX
DIV BX ; AX = cilindro, DX = resto
MOV [SI].cilindro,AL
MOV AX,DX
XOR DX,DX
DIV [SI].sectores_pista ; AX = cabezal, DX = sector
MOV [SI].cabezal,AL
INC DL
MOV sector_ini,DL
calcula_dir ENDP
procesa_io PROC
MOV AX,[SI].sectores_pista
SUB AL,sector_ini
INC AL ; AX sectores hasta fin pista
final: CMP AL,CL
JBE nsect_fp
MOV AL,CL ; ¡no hay que acceder a tantos!
nsect_fp: MOV AH,sector_ini
ADD AH,AL
DEC AH
MOV sector_fin,AH ; sector ini/fin inicializados
PUSH DS ; *
XOR BX,BX
MOV DS,BX
LDS BX,DS:[1Eh*4] ; DS:BX -> tabla base disco
CMP [BX+4],AH
JAE ultsec_ok
MOV [BX+4],AH ; sectores/pista necesarios
ultsec_ok: MOV BYTE PTR DS:[BX+5],1 ; GAP R/W mínimo
POP DS ; *
XOR AH,AH
SUB CX,AX ; restar los que se accederán
PUSH CX
MOV CX,3 ; 3 intentos como máximo
reintentar_io: PUSH CX
MOV AH,orden
MOV CL,sector_ini
MOV AL,sector_fin
SUB AL,CL
INC AL
MOV CH,[SI].cilindro
MOV DH,[SI].cabezal
MOV DL,[SI].unidad
MOV BX,DI
PUSH AX
PUSHF
CALL ant_int13
POP BX
JC fallo_io ; ha habido fallo
CMP verificar,ON
CLC
JNE io_ok
MOV AH,4 ; verificar en write verify
MOV CL,sector_ini
MOV AL,sector_fin
SUB AL,CL
INC AL
MOV CH,[SI].cilindro
MOV DH,[SI].cabezal
MOV DL,[SI].unidad
MOV BX,DI
PUSH AX
PUSHF
CALL ant_int13
POP BX
JC fallo_io
JMP io_ok
fallo_io: POP CX
CMP AH,3
JE proc_io_nok ; protegido contra escritura
TEST AH,80h
JNZ proc_io_nok ; unidad no preparada
MOV AH,0
PUSH CX
PUSHF
CALL ant_int13 ; reset de disco
POP CX
LOOP reintentar_io
JMP proc_io_nok ; agotadas las oportunidades
io_ok: MOV AH,BL
SHL AH,1
MOV AL,0
ADD DI,AX ; ES:BX++
POP CX ; contador de intentos
POP CX ; sectores que restan
JCXZ fin_io ; ¿más sectores a transferir?
MOV sector_ini,1 ; ahora desde el primer sector
INC [SI].cabezal ; de la siguiente cara
MOV AX,[SI].num_cabezas
CMP [SI].cabezal,AL
JAE pr_step
JMP procesa_io
pr_step: MOV [SI].cabezal,0 ; o desde la primera cara
INC [SI].cilindro ; del siguiente cilindro
JMP procesa_io
fin_io: MOV AX,100h ; Ok.
RET
proc_io_nok: POP CX
LDS BX,pcab_peticion
MOV [BX].transfer_sect,0 ; movidos 0 sectores
MOV AH,1
MOV DL,CS:[SI].unidad
PUSHF
CALL CS:ant_int13 ; obtener código de error BIOS
CALL errbios2dos
RET ; retornar con código error DOS
procesa_io ENDP
; ------------ Traducir el error BIOS a código de error DOS.
errbios2dos PROC
MOV AL,0
CMP AH,3 ; ¿protegido contra escritura?
JE err_dos_ok
MOV AL,8
CMP AH,4 ; ¿sector no encontrado?
JE err_dos_ok
MOV AL,0Fh
CMP AH,6 ; ¿cambio de disco no permitido?
JE err_dos_ok
MOV AL,4
TEST AL,10h ; ¿error de CRC?
JNZ err_dos_ok
MOV AL,6
TEST AH,40h ; ¿fallo posicionando cabezal?
JNZ err_dos_ok
MOV AL,2
TEST AH,80h ; ¿unidad no preparada?
JNZ err_dos_ok
MOV AL,0Ch ; otro fallo: anomalía general
err_dos_ok: MOV AH,81h
RET
errbios2dos ENDP
; ------------ Lectura, escritura y verificación en disco 2MGUI.
; A la entrada, ES:DI=dirección, BX=sectini, CX=nsects.
rwv2mgui PROC
MOV AX,[SI].bytes_sector
MUL BX ; DX:AX = sector * tamaño
XPUSH <CX, AX, DX> ; *
MOV AX,[SI].infb.tpista1
MOV BL,[SI].infb.mfrontera
MOV BH,0
SHL BX,1
MUL BX ; DX:AX = tpista1 * frontera * 2
XPOP <CX, BX> ; * CX:BX = offset en disco
SUB BX,AX
SBB CX,DX
MOV [SI].cilindro,0 ; primera parte del disco
JC rwv_cil_ok
MOV AL,[SI].infb.mfrontera
MOV [SI].cilindro,AL ; segunda parte del disco
JMP rwv_off_ok
rwv_cil_ok: ADD BX,AX
ADC CX,DX ; restaurar offset
rwv_off_ok: MOV DX,CX
CALL tpistaAX
XCHG AX,BX ; offset en DX:AX, BX = tpista
POP CX ; *
SHL BX,1 ; BX = tpista * 2
DIV BX
ADD [SI].cilindro,AL ; cilindro inicial
MOV AX,DX
XOR DX,DX ; DX:AX = resto división
SHR BX,1
DIV BX
MOV [SI].cabezal,AL ; cabezal inicial
MOV off_ini,DX ; offset inicial
MOV AX,[SI].bytes_sector
MUL CX
MOV bytes,AX ; bytes a transferir
MOV CX,3 ; reintentos en caso de error
trans_mas: CMP bytes,0
JE fin_trans
PUSH CX
CALL tpistaAX
SUB AX,off_ini ; AX = bytes hasta final pista
CMP AX,bytes
JB ttrans_prep ; ocupa la pista hasta el final
MOV AX,bytes
ttrans_prep: ADD AX,off_ini
MOV off_fin,AX
CALL haz_io
POP CX
JNC ttrans_ok
CMP status,3 ; error grave (prot. escrit.)
JE err_trans
TEST status,80h
JNZ err_trans ; error grave (no preparada)
CALL reset_drv
LOOP trans_mas
JMP err_trans ; fin de reintentos
ttrans_ok: INC [SI].cabezal
CMP [SI].cabezal,2
JB incs_ok
MOV [SI].cabezal,0
INC [SI].cilindro
incs_ok: MOV AX,off_fin
SUB AX,off_ini
MOV off_ini,0
SUB bytes,AX
JMP trans_mas
err_trans: CLC
CALL motor_off_cnt ; cuenta detención motor
LDS BX,pcab_peticion
MOV [BX].transfer_sect,0 ; movidos 0 sectores
MOV AH,CS:status
CALL errbios2dos
RET
fin_trans: CLC
CALL motor_off_cnt ; cuenta detención motor
MOV AX,100h
RET
rwv2mgui ENDP
; --- Transferir desde off_ini a off_fin
haz_io PROC
CALL direcc_ems ; direccionar memoria EMS
JNC dirb_ok
JMP ret_io ; fallo
dirb_ok: CMP orden,BIOS_READ
JNE escribir
CALL leida?
JNC upd_ok
RET ; fallo en el flush
upd_ok: JZ ahorra_lect ; pista ya leída
CALL motor_ok
CALL seek_drv
CALL lee_pista
CALL anotar_acceso
JNC ahorra_lect
RET ; fallo al leer
ahorra_lect: MOV CX,off_fin
SUB CX,off_ini
XPUSH <DS, SI>
MOV SI,off_ini
MOV DS,sbuffer
CLD
REP MOVSB
XPOP <SI, DS>
CLC
JMP ret_io
escribir: CALL leida?
JC ret_io ; fallo en el flush
MOV CX,off_fin
SUB CX,off_ini
CALL tpistaAX
CMP CX,AX
JE escr_fast ; escribir pista completa
CALL leida?
JZ escr_fast ; pista ya en el buffer
CALL motor_ok
CALL seek_drv
CALL lee_pista ; parcial: prelectura
CALL anotar_acceso
JC ret_io
escr_fast: XPUSH <ES, DI> ; *
XPUSH <DS, SI> ; **
XPUSH <ES, DI>
XPOP <SI, DS>
MOV DI,CS:off_ini
MOV ES,CS:sbuffer
PUSH CX
CLD
REP MOVSB
POP CX
XPOP <SI, DS> ; **
PUSH AX ; **
MOV AL,[SI].cilindro
OR AL,[SI].cabezal
JNZ escr
XPUSH <SI, CX> ; ***
LEA SI,[SI].infb
MOV DI,PINFOBOOT
MOV CX,TYPE InfoBoot
CLD
REP MOVSB ; palabras de sólo lectura :-)
XPOP <CX, SI> ; ***
escr: POP AX ; **
XPOP <DI, ES> ; *
CALL escribir_pista ; "escribir" pista en disco
CALL anotar_acceso
JC ret_io
ADD DI,CX ; actualizar offset
CLC
ret_io: RET
haz_io ENDP
; --- Mapear memoria EMS si es utilizada.
direcc_ems PROC
PUSH SI
CMP ems_handle,0
JE seg_io_ok ; no usada EMS
MOV AX,DI
MOV CL,4
SHR AX,CL
MOV CX,ES
ADD AX,CX ; AX = dirección lineal ES:DI
MOV CX,marco_ems
ADD CX,1024 ; CX = base página 1
MOV BL,2 ; intentar usar página 2
MOV DX,2048 ; offset de la página física 2
CMP AX,CX
JB map_pag
XOR BL,BL ; usar la 0 para no colisionar
MOV DX,0 ; offset de la página física 0
map_pag: ADD DX,marco_ems
MOV sbuffer,DX
rmap_pag: MOV DX,ems_handle
MOV AL,BL ; página física
MOV AH,44h
MOV BX,0 ; primera página lógica
PUSH AX
INT 67h ; mapear página
POP BX
CMP AH,82h
JE rmap_pag ; reintentar
AND AH,AH
JNZ seg_io_ko
CMP tbuffer,16384
JBE seg_io_ok ; buffer de hasta 16K
INC BL ; siguiente página física
rmap2: MOV AL,BL
MOV AH,44h
MOV BX,1 ; segunda página lógica
MOV DX,ems_handle
PUSH AX
INT 67h ; mapear página
POP BX
CMP AH,82h
JE rmap2 ; reintentar
AND AH,AH
JNZ seg_io_ko
seg_io_ok: CLC ; Ok
POP SI
RET
seg_io_ko: MOV status,20h
STC ; fallo
POP SI
RET
direcc_ems ENDP
; --- Vaciar buffer a disco. Si se trabaja con EMS,
; previamente se mapea la memoria.
abs_flush PROC
CLI
CMP wrpend,ON
JE _abs_flush
STI
CLC
RET
_abs_flush: MOV wrpend,OFF
STI
CMP ems_handle,0
JNE flush_ems
JMP _flush_cache ; no usada memoria EMS
flush_ems: MOV DX,ems_handle ; usada memoria EMS
MOV AH,47h
INT 67h ; preservar el contexto
CMP AH,82h
JE flush_ems ; reintentar
AND AH,AH
JNZ absf_ret
CALL direcc_ems
CALL _flush_cache
PUSH AX
rrst2: MOV DX,ems_handle
MOV AH,48h
INT 67h ; restaurar el contexto
CMP AH,82h
JE rrst2 ; reintentar
POP AX
absf_ret: RET
abs_flush ENDP
; --- Vaciar buffer a disco. La escritura efectiva se
; retarda para reducir accesos redundantes.
flush_cache PROC
CLI
CMP wrpend,ON
JE _flush_cache
STI
CLC
RET
_flush_cache: MOV wrpend,OFF
STI
PUSH SI
LEA SI,info_BUF
CMP [SI].unidad,-1
JE fc_ret
CALL motor_ok
CALL seek_drv
CALL escribe_pista
CALL anotar_acceso
fc_ret: POP SI
RET
flush_cache ENDP
; --- Simular escritura en disco, aunque realmente se
; hará normalmente más tarde ("delayed write") a
; menos que esté activa la verificación.
escribir_pista PROC
CMP [SI].prot_esc,ON
JNE wr_posible
MOV status,3 ; protegida de escritura
STC
RET
wr_posible: CMP verificar,ON
JE wr_fisico ; verificación activa...
CMP cachewr,ON
JE delayed_wr
wr_fisico: CALL motor_ok ; caché desactivada
CALL seek_drv
CALL escribe_pista
JC wr_fs_ret
CMP verificar,OFF
JE wr_fs_ret ; CF=0
CALL lee_pista ; detectar posible fallo
wr_fs_ret: RET
delayed_wr: MOV expiraw,W_CACHE_TM ; recargar contador de
MOV wrpend,ON ; tiempo para escritura
CLC ; retardada
RET
escribir_pista ENDP
; ------------ Comprobar si la pista está en el buffer. En caso de
; estarlo se retorna con ZF=1. Si no estaba aún, se
; vacía el contenido del buffer (si aún no estaba
; escrito en disco) en previsión de una futura
; lectura, retornando con ZF=0 (ó CF=1 si hay error
; al escribir).
leida? PROC
PUSH AX
MOV AL,info_BUF.unidad
CMP AL,[SI].unidad
JNE no_leida ; es en otra unidad
MOV AL,[SI].cilindro
CMP AL,info_BUF.cilindro
JNE no_leida
MOV AH,[SI].cabezal
CMP AH,info_BUF.cabezal
JNE no_leida ; es en otro cilindro/cabezal
POP AX
RET ; está en el buffer CF=0, ZF=1
no_leida: CALL flush_cache
JC ret_leida? ; CF = 1 si error en el flush
CMP SP,0
CLC ; CF = ZF = 0
ret_leida?: POP AX
RET ; pista no leída
leida? ENDP
; --- Tomar nota de la pista que ocupa el buffer para
; evitar accesos a disco redundantes. A la entrada,
; CF=1 señala error e invalida el buffer. Se anotan
; también los demás parámetros, necesarios para una
; posible escritura desde la interrupción periódica.
anotar_acceso PROC
MOV info_BUF.unidad,-1 ; invalidar buffer si error
JC anotado
XPUSH <CX, SI, DI, ES>
PUSH DS
POP ES
LEA DI,info_BUF
MOV CX,TYPE info_unidad
CLD
REP MOVSB
XPOP <ES, DI, SI, CX>
CLC
anotado: RET
anotar_acceso ENDP
; ------------ Devolver el tamaño de la pista según la posición
; del cabezal (necesario en discos /DH).
tpistaAX PROC
MOV AL,CS:[SI].infb.mfrontera
CMP CS:[SI].cilindro,AL
MOV AX,CS:[SI].infb.tpista1
JB tpis_ax
MOV AX,CS:[SI].infb.tpista2
tpis_ax: RET
tpistaAX ENDP
; ------------ Asegurar que el motor está en marcha.
motor_ok PROC
XPUSHA ; *
PUSH DS ; **
MOV BX,40h
PUSH BX
POP DS
MOV CH,255-18 ; CH = 255 - 1 segundo
CLI
MOV CL,CS:[SI].unidad
MOV AL,1
SHL AL,CL
TEST [BX-1],AL ; ¿motor en marcha?
JZ arrancarlo ; arrancarlo
CMP [BX],CH ; Si encendido y acelerado...
JBE ok_motor ; ...seguir
arrancarlo: MOV AH,CL
MOV CL,4
SHL AH,CL ; unidad << 4
OR AL,AH
MOV [BX-1],AL ; nuevo estado motores
MOV BYTE PTR [BX],255 ; asegurar que no se pare
MOV DX,FD_DOR ; registro de salida digital
ADD CL,CS:[SI].unidad
MOV AL,1
SHL AL,CL ; colocar bit del motor
OR AL,CS:[SI].unidad ; seleccionar unidad
OR AL,00001100b ; modo DMA, no hacer reset
OUT DX,AL ; poner en marcha el motor
STI
MOV AX,90FDh
CLC
INT 15h ; permitir multitarea
JC ok_motor ; timeout
MOV AX,1000 ; 1 segundo aceleración
CALL retardo ; esperar aceleración disco
ok_motor: MOV [BX],CH ; cuenta máxima detención motor
STI ; sin forzar futura aceleración
POP DS ; **
XPOPA ; *
RET
motor_ok ENDP
; ------------ Establecer modalidad de operación del controlador
; y poner el motor en marcha. Si CF=1 se le da tiempo
; además a la unidad para que acelere.
reset_drv PROC
XPUSHA
CALL motor_off_cnt ; cuenta detención motor
STC
CALL set_rate ; velocidad correcta
MOV CL,[SI].unidad
MOV AL,CL ; unidad seleccionada
SHL AL,1
SHL AL,1
SHL AL,1
SHL AL,1
MOV AH,1 ; bit de motor
SHL AH,CL ; colocar dicho bit
OR AL,AH
PUSH DS ; *
DDS
CLI
MOV DS:[3Fh],AL
AND BYTE PTR DS:[3Eh],70h ; bit IRQ=0 y recalibrar
POP DS ; *
SHL AL,1
SHL AL,1
SHL AL,1
SHL AL,1 ; bits motor en nibble alto
OR AL,CL ; seleccionar unidad
OR AL,00001000b ; interrupciones+DMA y reset
MOV DX,FD_DOR ; registro de salida digital
OUT DX,AL ; señal de reset
CALL fdc_respiro ; tiempo reconocer reset en 486
OR AL,00000100b
OUT DX,AL ; fin de señal de reset
CALL reset_DMA
CALL reset_irq
CALL espera_int ; rehabilitará interrupciones
AND status,7Fh ; perdonar controladora rara
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
CALL fdc_read
CALL fdc_read
STC
CALL envia_specify ; comando 'specify' adecuado
XPOPA
RET
reset_drv ENDP
; ------------ Reset "blando" para que el FDC deje de enviar/recibir.
reset_fast PROC
XPUSHA
MOV CL,[SI].unidad
ADD CL,4
MOV AL,1
SHL AL,CL ; bits motor en nibble alto
OR AL,[SI].unidad ; seleccionar unidad
OR AL,00001000b ; interrupciones+DMA y reset
MOV DX,FD_DOR ; registro de salida digital
CLI
OUT DX,AL ; señal de reset
CALL fdc_respiro ; tiempo reconocer reset en 486
OR AL,00000100b
OUT DX,AL ; fin de señal de reset
CALL reset_DMA
CALL reset_irq
CALL espera_int ; rehabilitará interrupciones
AND status,7Fh ; perdonar controladora rara
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
CALL fdc_read
CALL fdc_read
STC
CALL envia_specify ; comando 'specify' con DMA
XPOPA
RET
reset_fast ENDP
; ------------ Desactivar el modo DMA si procede (antes de leer o
; escribir). Además de enviar al FDC el comando specify
; adecuado, se selecciona el modo no-DMA (si fuera
; preciso) en el registro de salida digital (necesario en
; algunas controladoras).
dma_si_o_no PROC
CMP modoDMA,ON
JE dmsnret
XPUSHA
MOV CL,[SI].unidad
ADD CL,4
MOV AL,1
SHL AL,CL ; bits motor en nibble alto
OR AL,[SI].unidad ; seleccionar unidad
OR AL,00000100b ; modo no-DMA, sin reset
MOV DX,FD_DOR
OUT DX,AL
CLC
CALL envia_specify ; comando 'specify' adecuado
XPOPA
dmsnret: RET
dma_si_o_no ENDP
; ------------ Inhibir y borrar petición en el canal 2 de DMA. No es
; realmente necesario, porque la controladora ya no
; transmite más después del reset, es sólo por seguridad.
reset_DMA PROC
PUSH AX
MOV AL,2
DELAY
OUT 09h,AL ; borrar petición por software
MOV AL,6
DELAY
OUT 0Ah,AL ; inhibir canal 2
POP AX
RET
reset_DMA ENDP
; ------------ Borrar bit de interrupción pendiente para asegurar
; su correcta detección si llegó antes alguna inesperada,
; aunque realmente no tiene por qué suceder.
reset_irq PROC
PUSHF
PUSH DS
DDS
AND BYTE PTR DS:[3Eh],7Fh ; asegurar detección int.
POP DS
POPF
RET
reset_irq ENDP
; ------------ Enviar comando specify a la controladora. El step-rate
; se selecciona según la densidad, para evitar un sonido
; extraño al posicionar o recalibrar el cabezal. A la
; entrada, CF=1 selecciona modo DMA y 0 no-DMA
envia_specify PROC
PUSH AX ; *
PUSHF ; **
PUSH DS
DDS
MOV AH,DS:[8Bh]
POP DS
MOV AL,3 ; comando 'specify'
CALL fdc_write
MOV AL,0BFh ; step rate para 500 kbps
AND AH,11000000b
JZ spec1_ok
MOV AL,0AFh ; step rate para 1 Mbps
CMP AH,11000000b
JE spec1_ok
MOV AL,0DFh ; step rate para 250/300 Kbps
spec1_ok: CALL fdc_write
MOV AL,2 ; modo DMA
POPF ; **
JC spec2_ok
MOV AL,3 ; modo no DMA
spec2_ok: CALL fdc_write
POP AX ; *
RET
envia_specify ENDP
; ------------ Recargar cuenta para la detención del motor. Si CF=1 al
; entrar, se establece la mayor cuenta posible; en caso
; contrario, se pone el valor normal de la tabla base.
motor_off_cnt PROC
XPUSHA
PUSH DS
MOV AL,0FFh ; valor máximo
JC motor_off_ok
XOR BX,BX
MOV DS,BX
LDS BX,DWORD PTR DS:[1Eh*4] ; DS:BX -> INT 1Eh
MOV AL,[BX+2] ; byte 2 tabla base disco
motor_off_ok: DDS
MOV BYTE PTR DS:[40h],AL ; cuenta parada motor
POP DS
XPOPA
RET
motor_off_cnt ENDP
; ------------ Llevar el cabezal a la pista indicada, recalibrando si
; hubo un reset (se invocó la función 0 de la INT 13h o
; se ejecutó reset_drv) antes de esta operación. Primero
; se selecciona la velocidad de transferencia y se borra
; el resultado de cualquier operación anterior, para que
; todo quede listo para el próximo acceso a disco.
seek_drv PROC
XPUSHA
CLC
CALL set_rate ; velocidad / borrar resultados
STC
CALL envia_specify ; comando 'specify' adecuado
MOV AH,1
MOV CL,[SI].unidad
SHL AH,CL ; AH = 1 (A:) ó 2 (B:)
PUSH DS
DDS
TEST AH,DS:[3Eh]
POP DS
JNZ do_seek ; la unidad ya fue recalibrada
CALL recalibrar
JC fallo_seek ; fallo al recalibrar
do_seek: CMP [SI].cilindro,0
JNE seek_deveras
CALL recalibrar ; ir a la pista 0
JMP seek_ok
seek_deveras: MOV BX,94h
ADD BL,[SI].unidad
MOV AL,[SI].cilindro
PUSH DS ; *
DDS
MOV CH,[BX] ; cilindro previo
MOV [BX],AL ; nuevo cilindro
POP DS ; *
CMP AL,CH
JE seek_ret ; seek innecesario
hacer_seek: SUB AL,CH
JC seek_neg ; seek hacia atrás
seek_pos: CALL seek_fisico ; seek hacia delante
JC fallo_seek
JMP seek_ok
seek_neg: ADD AL,CH
CALL recalibrar ; ir a la pista 0
MOV [SI].cilindro,AL
JC fallo_seek
JMP seek_deveras ; y luego a donde sea
seek_ok: MOV AX,15 ; 15 milisegundos
CALL retardo ; esperar asentamiento cabezal
seek_ret: CLC ; retornar con éxito
ret_seek: XPOPA
RET
fallo_seek: XPOPA
STC ; retornar indicando fallo
RET
; --- Como el registro interno de la controladora se
; pone a 0 tras el reset, el seek es por importe
; de la diferencia entre el cilindro origen y el
; destino (para retroceder se recalibra antes).
seek_fisico: MOV CH,AL ; magnitud del "salto"
MOV AL,0Fh
CALL fdc_write ; comando 'seek'
JC sk_fs_nok
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL fdc_write ; enviar HD, US1, US0
MOV AL,CH ; cilindro aparente
CALL reset_irq
CALL fdc_write ; enviar cilindro
CALL espera_int ; esperar interrupción
JC sk_fs_nok
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
JC sk_fs_nok
CALL fdc_read ; leer registro de estado 0
JC sk_fs_nok
MOV AH,AL
CALL fdc_read ; leer cilindro actual
TEST AH,11000000b ; comprobar ST0
JNZ sk_fs_nok
sk_fs_ok: CLC
RET
sk_fs_nok: STC
RET
seek_drv ENDP
; ------------ Establecer velocidad de transferencia correcta si aún
; no ha sido seleccionada y borrar el resultado de otra
; operación previa. Si CF=1 al entrar, la velocidad se
; establece incondicionalmente (por si la variable de
; la BIOS no está correctamente asignada).
set_rate PROC
XPUSHA
PUSHF
MOV AL,[SI].infb.mfrontera
CMP [SI].cilindro,AL
MOV AL,[SI].vunidad1 ; velocidad primera parte
MOV AH,[SI].infb.vunidad2 ; velocidad segunda parte
JB vel_ok
MOV AL,AH
vel_ok: POPF
PUSH DS ; *
DDS
JC abs_rate
MOV AH,DS:[8Bh]
MOV CL,6
SHR AH,CL ; aislar bits de velocidad
CMP AL,AH
JE vel_set ; velocidad ya seleccionada
abs_rate: MOV DX,FD_DCR
OUT DX,AL ; seleccionarla
MOV CL,6
SHL AL,CL
AND BYTE PTR DS:[8Bh],00111111b
OR DS:[8Bh],AL
vel_set: POP DS ; *
LEA DI,status
MOV CX,8
borra_status: MOV [DI],CH ; borrar información de estado
INC DI
LOOP borra_status
XPOPA
RET
set_rate ENDP
; ------------ Recalibrar la unidad (si hay error se intenta otra vez
; para el caso de que deba moverse más de 77 pistas).
recalibrar PROC
XPUSHA
MOV BX,94h
ADD BL,[SI].unidad
PUSH DS ; *
DDS
MOV [BX],BH ; pista actual = 0
POP DS ; *
MOV CX,2 ; dos veces como mucho
recalibra: MOV AL,7
CALL fdc_write ; comando de 'recalibrado'
JC fallo_recal
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL reset_irq
CALL fdc_write ; enviar HD, US1, US0
JC fallo_recal
CALL espera_int ; esperar interrupción
JC fallo_recal
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
JC fallo_recal
CALL fdc_read ; leer registro de estado 0
JC fallo_recal
MOV AH,AL
CALL fdc_read ; leer cilindro actual
XOR AH,00100000b ; bajar bit de 'seek end'
TEST AH,11110000b ; comprobar resultado y ST0
JNZ fallo_recal ; sin 'seek end' o TRK0
MOV AX,1 ; pausa de 1 ms
CALL retardo
JMP recal_ret
fallo_recal: CALL reset_fast
LOOP recalibra ; reintentar comando
STC ; condición de fallo
XPOPA
RET
recal_ret: MOV AH,1
MOV CL,[SI].unidad
SHL AH,CL ; AH = 1 (A:) ó 2 (B:)
MOV BX,94h
ADD BL,CL
PUSH DS
DDS
OR DS:[3Eh],AH ; unidad ya recalibrada
POP DS
CLC
XPOPA
RET
recalibrar ENDP
; ------------ Escribir pista. En modo test (gaprw == -1) se escriben
; sólo los bytes de la pista (sin almacenar el checksum
; ni el GAP anti-FIFO).
escribe_pista PROC
XPUSHA
CALL dma_si_o_no ; modo no-DMA si es preciso
PUSH ES ; *
MOV ES,sbuffer
CALL tpistaAX
MOV CX,AX
XOR BX,BX
XOR AX,AX
MOV DX,2
SHR CX,1
PUSHF
calc_chk: ADD AX,ES:[BX] ; calcular checksum en AX
ADD BX,DX
LOOP calc_chk
POPF
JNC fcalc_chk
ADD AL,ES:[BX] ; nº de bytes impar
ADC AH,0
INC BX
fcalc_chk: MOV CX,gaprw
CMP CX,-1
JE wfis1
NOT AX
MOV ES:[BX],AX ; NOT (checksum)
JCXZ wfis1
MOV AL,0
gapw: MOV ES:[BX+2],AL ; "GAP"
INC BX
LOOP gapw
wfis1: POP ES ; *
CALL tpistaAX
CMP gaprw,-1 ; ¿escritura de test?
JE wfis2
ADD AX,SYSBYTES
ADD AX,gaprw ; bytes extra tras datos
wfis2: MOV CX,AX
DEC CX ; bytes totales - 1
MOV AX,sbuffer
XOR DI,DI
CALL calc_dir_DMA ; AX:DI -> base BX y página AH
MOV AL,F_WRITE ; modo DMA necesario
CALL prepara_DMA
MOV AL,11000101b ; comando de escritura del FDC
CALL fdc_write
JC escr_ko
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL fdc_write ; byte 1 de la orden
MOV AL,[SI].cilindro
CALL fdc_write ; enviar cilindro
MOV AL,[SI].cabezal
CALL fdc_write ; enviar cabezal
MOV AL,0
CALL fdc_write ; enviar nº sector
MOV AL,[SI].tsector
CALL fdc_write ; longitud sector
MOV AL,0
CALL fdc_write ; último sector
MOV AL,8
CALL fdc_write ; GAP no usado, pero...
MOV AL,128
CLI ; ir inhibiéndolas ya
CALL fdc_write ; tamaño sector si longitud=0
CALL espia_dma
JMP escr_ret
escr_ko: STC ; indicar fallo
escr_ret: XPOPA
RET
escribe_pista ENDP
; ------------ Leer pista. En modo test (gaprw == -1) no se leen los
; bytes finales con el checksum (aunque sí se comparan al
; final: el error se debe desechar y comprobar el éxito
; de otra manera).
lee_pista PROC
XPUSHA
CALL dma_si_o_no ; modo no-DMA si es preciso
CALL tpistaAX
CMP gaprw,-1
JE rfis ; lectura de test
ADD AX,SYSBYTES
ADD AX,gaprw ; bytes extra tras datos
rfis: MOV CX,AX
DEC CX ; bytes totales - 1
MOV AX,sbuffer
XOR DI,DI
CALL calc_dir_DMA ; AX:DI -> base BX y página AH
MOV AL,F_READ ; modo DMA necesario
CALL prepara_DMA
MOV AL,11100110b ; comando de lectura del FDC
CALL fdc_write
MOV DL,20h
JC leer_err
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL fdc_write ; byte 1 de la orden
MOV AL,[SI].cilindro
CALL fdc_write ; enviar cilindro
MOV AL,[SI].cabezal
CALL fdc_write ; enviar cabezal
MOV AL,0
CALL fdc_write ; enviar nº sector
MOV AL,[SI].tsector
CALL fdc_write ; longitud sector
MOV AL,0
CALL fdc_write ; último sector
MOV AL,8
CALL fdc_write ; GAP no usado, pero...
MOV AL,128
CLI ; ir inhibiéndolas ya
CALL fdc_write ; tamaño sector si longitud=0
CALL espia_dma
JC leer_ret ; hubo error
PUSH ES ; *
MOV ES,sbuffer
CALL tpistaAX
MOV CX,AX
XOR BX,BX
XOR AX,AX
MOV DX,2
SHR CX,1
PUSHF
test_chk: ADD AX,ES:[BX] ; calcular checksum en AX
ADD BX,DX
LOOP test_chk
POPF
JNC ftest_chk
ADD AL,ES:[BX] ; nº de bytes impar
ADC AH,0
INC BX
ftest_chk: NOT AX ; NOT (checksum)
MOV CX,ES:[BX] ; checksum en disco en CX
POP ES ; *
MOV DL,10h ; 'error de CRC'
CMP AX,CX
JNE leer_err
CLC ; Ok
JMP leer_ret
leer_err: OR status,DL
STC ; indicar fallo
leer_ret: XPOPA
RET
lee_pista ENDP
; ------------ Cuando el DMA acabe... resetear controladora. A la
; entrada, las interrupciones deben estar inhibidas.
; Si no se emplea el DMA ... se resetea cuando se han
; enviado/recibido directamente los bytes necesarios.
; Se reprograma el 8254 para asegurar a ultranza que
; produce las 18,2 irqs/seg habituales y para contar
; exactamente el tiempo que pasará en esta rutina: la
; pérdida de exactitud que supone recargar la cuenta
; no se puede comparar ni remotamente a la de tener
; las interrupciones inhibidas ;-)
espia_dma PROC
XPUSH <ES, DI> ; *
MOV ES,sbuffer
MOV AL,00010110b
OUT 43h,AL ; 8254: cnt0 byte bajo
MOV AL,0
DELAY
OUT 40h,AL ; asegurar recarga = 0000h
MOV AL,00100110b
DELAY
OUT 43h,AL ; 8254: cnt0 byte alto
MOV AL,0
DELAY
OUT 40h,AL ; asegurar recarga = 0000h
DELAY
IN AL,40h
MOV BL,AL ; estado de la cuenta alta
MOV DX,FD_STATUS
MOV CX,TICSTIMEOUT ; constante de timeout
CMP modoDMA,ON
JE wait_dma
XOR DI,DI ; ES:DI -> sbuffer
MOV AH,BL
MOV BX,bytesIO
CMP sentidoIO,F_READ
JE rd_nodma
wr_nodma: IN AL,DX ; transferencia sin DMA
TEST AL,10000000b
JNZ wr_byte
IN AL,40h
CMP AL,AH
JE wr_nodma ; no han pasado 256/1193180 seg
MOV AH,AL
LOOP wr_nodma
JMP io_timeout
wr_byte: TEST AL,01000000b ; ¿fdc->cpu en vez de cpu->fdc?
JNZ io_result ; así es: fallo en escritura
MOV AL,ES:[DI]
INC DX ; apuntar al registro de datos
OUT DX,AL ; escribir byte de la pista
DEC DX
INC DI
DEC BX
JNZ wr_nodma ; hasta acabar pista
JMP io_fin
rd_nodma: IN AL,DX ; transferencia sin DMA
TEST AL,10000000b
JNZ rd_byte
IN AL,40h
CMP AL,AH
JE rd_nodma ; no han pasado 256/1193180 seg
MOV AH,AL
LOOP rd_nodma
JMP io_timeout
rd_byte: TEST AL,00100000b ; ¿fase de ejecución?
JZ io_result ; no: fallo en lectura
INC DX ; apuntar al registro de datos
IN AL,DX ; leer byte de la pista
DEC DX
STOSB
DEC BX
JNZ rd_nodma ; hasta acabar pista
JMP io_fin
wait_dma: IN AL,DX ; transferencia con DMA
XOR AL,11000000b
TEST AL,11000000b
JZ io_result ; hay resultados del FDC
IN AL,5
MOV AH,AL
IN AL,5 ; contador del canal 2
CMP AX,-1
JE io_fin ; fin de la cuenta del DMA
IN AL,40h
CMP AL,BL
JE wait_dma ; no han pasado 256/1193180 seg
MOV BL,AL
LOOP wait_dma
io_timeout: CALL reset_fast ; habilita ints (quita timeout)
MOV status,80h ; recuperar condición timeout
JMP io_ret_nok
io_fin: IN AL,DX
XOR AL,11000000b
TEST AL,11000000b
JZ io_result ; hay resultados del FDC
CALL reset_fast ; habilita ints
JMP io_ret_ok ; siempre ok
io_result: CALL reset_DMA ; por si acaso
STI
LEA BX,fdc_result
PUSH CX ; ** no corromper CX
MOV CX,7
io_leeres: CALL fdc_read ; leyendo resultados
MOV [BX],AL
INC BX
LOOP io_leeres
POP CX ; **
CMP modoDMA,ON
JE io_ret_nok
MOV AL,status ; preservar resultado
CALL reset_fast ; volver al modo DMA+INT
MOV status,AL ; restaurar resultado
io_ret_nok: CALL ajustar_hora
XPOP <DI, ES> ; *
STC ; retorno con error
CALL set_err
RET
io_ret_ok: XPOP <DI, ES> ; *
CALL ajustar_hora
CLC ; retorno Ok
RET
espia_dma ENDP
; ------------ Leer el reloj de tiempo real y actualizar la hora.
; El acceso a disco con las interrupciones inhibidas
; retrasa brutalmente la hora. Si es un PC/XT, a la
; entrada CX indica las veces que le quedaban por cambiar
; a la parte alta de la cuenta del contador 0 del 8253
; desde que se inhibieron las interrupciones para que
; se hubiera producido un timeout.
ajustar_hora PROC
XPUSHA
CMP CS:pcxt,ON
JE ajuste_burdo ; jeje, pobrecillo XT
CALL leer_RTC
JNC actualiza_tm ; no hay actualización en curso
JMP fin_ajuste
ajuste_burdo: SUB CX,TICSTIMEOUT
NEG CX ; tiempo transcurrido apróx.
ADD CX,48 ; redondeo
MOV CL,CH
MOV CH,0
SHR CX,1 ; expresado en 1/18,2-avos seg.
PUSH DS
DDS
ADD CX,DS:[6Ch]
MOV BX,DS:[6Eh]
ADC BX,0
POP DS
JMP ajusta_bios
actualiza_tm: MOV AL,DH ; segundos en BCD
CALL convdec ; BCD (AL) -> decimal (AX)
PUSH AX ; almacenar segundos
MOV AL,CL ; minuto en BCD
CALL convdec ; BCD (AL) -> decimal (AX)
PUSH AX ; almacenar minuto
MOV AL,CH ; hora en BCD
CALL convdec ; BCD (AL) -> decimal (AX)
MOV BX,60
MUL BL ; AX = hora*60
POP DX
ADD AX,DX ; AX = hora*60+minuto
MUL BX ; DX:AX = (hora*60+minuto)*60
POP CX
ADD CX,AX ; añadir segundos
ADC DX,0
MOV BX,DX ; BX:CX segundos totales
MOV SI,CX
MOV DI,BX ; DI:SI segundos totales
MOV AX,18 ; (1193180 DIV 65536)
CALL mult32x16 ; DI:SI = seg * 18
XCHG SI,CX
XCHG DI,BX ; BX:CX:XX = seg * 18 * 65536
MOV AX,13532 ; (1193180 MOD 65536)
CALL mult32x16
ADD CX,DI
ADC BX,0 ; BX:CX:SI = seg * 1193180
ajusta_bios: PUSH DS
DDS
CMP BX,24
JNE medianoche_ok
CMP CX,176
JB medianoche_ok
XOR BX,BX
SUB CX,176
INC BYTE PTR DS:[70h] ; paso 23:59:59 --> 00:00:00
medianoche_ok: MOV DS:[6Ch],CX
MOV DS:[6Eh],BX ; BX:CX = seg * 1193180 / 65536
POP DS
fin_ajuste: XPOPA
RET
convdec: MOV AH,AL ; BCD en AL --> decimal en AX
SHR AH,1
SHR AH,1
SHR AH,1
SHR AH,1
AND AL,15
AAD
RET
ajustar_hora ENDP
; --- Obtener la hora del reloj de tiempo real SIN BIOS.
leer_RTC PROC
MOV AL,0Ah ; registro de estado A
OUT 70h,AL
DELAY
IN AL,71h
TEST AL,128
JNZ tm_nok ; en medio de actualización
MOV AL,4
DELAY
OUT 70h,AL
DELAY
IN AL,71h
MOV CH,AL ; hora
MOV AL,2
DELAY
OUT 70h,AL
DELAY
IN AL,71h
MOV CL,AL ; minuto
MOV AL,0
DELAY
OUT 70h,AL
DELAY
IN AL,71h
MOV DH,AL ; segundo
CLC
RET
tm_nok: STC
RET
leer_RTC ENDP
; ------------ Rutina para multiplicar números de 32 por números de 16
; bits generando resultado de 48 bits: DXDISI = DISI * AX
mult32x16 PROC
PUSH AX
XCHG SI,AX ; multiplicador en SI
MUL SI ; AX (parte baja) * SI --> DXAX
XPUSH <DX, AX> ; preservar resultado parcial
MOV AX,DI
MUL SI ; AX (parte alta) * SI --> DXAX
XPOP <SI, DI> ; parte baja y media del resultado
ADD DI,AX ; acumular resultado intermedio
ADC DX,0 ; arrastrar posible acarreo
POP AX
RET
mult32x16 ENDP
; ------------ Devolver en AH la página de DMA y en BX la base. A la
; entrada, AX:DI -> dirección de memoria.
calc_dir_DMA PROC
PUSH DX
MOV BX,16
MUL BX
ADD AX,DI
ADC DX,0 ; DX:AX = dirección 20 bits
MOV BX,AX ; base en BX
MOV AH,DL ; página
dir_DMA_ok: POP DX
RET
calc_dir_DMA ENDP
; ------------ Determinar el tipo de error producido en el acceso.
set_err PROC
XPUSHA
JNC err_ret ; no hay error
CMP status,0 ; ¿'status' ya asignado?
JNE err_retc ; no cambiarlo si es así
MOV AL,BYTE PTR fdc_result+1
AND AL,10110111b ; aislar condiciones de test
LEA BX,lista_errs
MOV CX,9
busca_err: MOV AH,[BX] ; código de error BIOS
SHL AL,1
JC err_ok ; es ese error
INC BX
LOOP busca_err ; buscar otro error
err_ok: OR status,AH
err_retc: STC ; condición de error
err_ret: XPOPA
RET
set_err ENDP
; ------------ Esperar interrupción de disquete durante casi 2
; segundos antes de considerar que ha sido un fracaso.
espera_int PROC
STI
XPUSHA
XPUSH <DS, 40h>
POP DS
MOV AX,9001h
CLC
INT 15h ; permitir multitarea
JC timeout_int
MOV AH,0FFh
esperar_int: CMP AL,DS:[6Ch]
JE mira_int
MOV AL,DS:[6Ch]
INC AH
CMP AH,37 ; ¿más de 2 segundos?
JB mira_int
timeout_int: OR CS:status,80h ; timeout
STC
JMP fin_espera
mira_int: TEST BYTE PTR DS:[3Eh],80h
JZ esperar_int
AND BYTE PTR DS:[3Eh],7Fh ; CF=0
fin_espera: POP DS
XPOPA
RET
espera_int ENDP
; ------------ Preparar DMA para E/S. A la entrada, BX = dirección de
; base, AH = registro de página y CX = nº bytes - 1.
prepara_DMA PROC
CMP modoDMA,ON
JE _prepara_DMA
MOV sentidoIO,AL
MOV bytesIO,CX
INC bytesIO
RET ; modo NO-DMA
_prepara_DMA: PUSH AX
CLI
OUT 0Bh,AL ; registro de modo del DMA
MOV AL,0
DELAY
OUT 0Ch,AL ; clear first/last flip-flop
MOV AL,BL
DELAY
OUT 4,AL
MOV AL,BH
DELAY
OUT 4,AL ; enviada dirección base
DELAY
MOV AL,AH
OUT 81h,AL ; registro de página del DMA
MOV AL,CL
DELAY
OUT 5,AL
MOV AL,CH
DELAY
OUT 5,AL ; enviada cuenta de bytes
STI
MOV AL,2
DELAY
OUT 0Ah,AL ; habilitar canal 2 de DMA
POP AX
RET
prepara_DMA ENDP
; ------------ Recibir byte del FDC en AL. A la vuelta, CF=1 si
; la operación fracasó (el FDC no estaba listo) y
; se indica la condición de timeout en «status».
fdc_read PROC
CMP CS:pcxt,ON
JE fdc_read_xt
XPUSH <CX, DX, AX>
CALL fdc_respiro ; no abrasar el FDC
MOV DX,FD_STATUS ; registro de estado del FDC
MOV CX,133 ; constante para 0,002 segundos
espera_rd: DELAY
IN AL,DX
AND AL,11000000b
CMP AL,11000000b ; ¿dato listo?
JE fdc_rd_ok
DELAY
IN AL,61h
AND AL,10h
CMP AL,AH
JE espera_rd ; reintentarlo durante 15,09 µs
MOV AH,AL
LOOP espera_rd
XPOP <AX, DX, CX>
OR status,80h ; timeout
MOV AL,0
STC ; fallo
RET
fdc_rd_ok: POP AX
INC DX ; apuntar al registro de datos
DELAY
IN AL,DX ; leer byte del FDC
XPOP <DX, CX>
CLC ; Ok
RET
fdc_read ENDP
fdc_read_xt PROC
XPUSH <CX, DX>
MOV DX,FD_STATUS ; registro de estado del FDC
XOR CX,CX ; evitar cuelgue total si falla
espera_rd_xt: IN AL,DX ; leer registro de estado
TEST AL,80h ; ¿bit 7 inactivo?
LOOPZ espera_rd_xt ; así es: el FDC está ocupado
JCXZ fdc_rd_nok_xt
INC DX ; apuntar al registro de datos
IN AL,DX ; leer byte del FDC
CLC
XPOP <DX, CX>
RET
fdc_rd_nok_xt: OR status,80h ; timeout
STC
XPOP <DX, CX>
RET
fdc_read_xt ENDP
; ------------ Enviar byte AL al FDC. A la vuelta, CF=1 si
; la operación fracasó (el FDC no estaba listo) y
; se indica la condición de timeout en «status».
fdc_write PROC
CMP CS:pcxt,ON
JE fdc_write_xt
XPUSH <CX, DX, AX>
CALL fdc_respiro ; no abrasar el FDC
MOV DX,FD_STATUS ; registro de estado del FDC
MOV CX,133 ; constante para 0,002 segundos
espera_wr: DELAY
IN AL,DX
TEST AL,80h ; ¿listo para E/S?
JNZ fdc_wr_ok
DELAY
IN AL,61h
AND AL,10h
CMP AL,AH
JE espera_wr ; reintentarlo durante 15,09 µs
MOV AH,AL
LOOP espera_wr
XPOP <AX, DX, CX>
OR status,80h ; timeout
STC ; fallo
RET
fdc_wr_ok: INC DX ; apuntar al registro de datos
POP AX
DELAY
OUT DX,AL ; enviar byte al FDC
XPOP <DX, CX>
CLC ; Ok
RET
fdc_write ENDP
fdc_write_xt PROC
XPUSH <AX, CX, DX>
MOV DX,FD_STATUS ; registro de estado del FDC
XCHG AH,AL ; preservar AL en AH
XOR CX,CX ; evitar cuelgue total si falla
espera_wr_xt: IN AL,DX ; leer registro de estado
TEST AL,80h ; ¿bit 7 inactivo?
LOOPZ espera_wr_xt ; así es: el FDC está ocupado
JCXZ fdc_wr_nok_xt
XCHG AH,AL ; recuperar el dato de AL
INC DX ; apuntar al registro de datos
OUT DX,AL ; enviar byte al FDC
XPOP <DX, CX, AX>
CLC
RET
fdc_wr_nok_xt: OR status,80h ; timeout
XPOP <DX, CX, AX>
STC
RET
fdc_write_xt ENDP
; ------------ Retardo de 60 µs para dar tiempo al FDC en 486 rápidos.
fdc_respiro PROC
CMP CS:pcxt,ON
JNE fdc_resp_at
PUSH CX
MOV CX,50
respiro: LOOP respiro ; retardo en PC/XT
POP CX
RET
fdc_resp_at: XPUSH <AX, CX>
MOV CX,4
fdc_ret: PMICRO
LOOP fdc_ret
XPOP <CX, AX>
RET
fdc_respiro ENDP
; ------------ Esperar exactamente AX milisegundos.
retardo PROC
PUSHF
XPUSHA
CMP CS:pcxt,ON
JE retardo_xt
MOV DX,16970 ; 16970 = 1193180/18*256/1000
MUL DX
MOV CL,AH ; dividir DX:AX entre 256 y
MOV CH,DL ; dejar el resultado en DX:CX
MOV DL,DH
MOV DH,0 ; DX:CX 15,09 µs-avos
retardando: PMICRO
LOOP retardando
AND DX,DX
JZ retardado
DEC DX
JMP retardando
retardado: XPOPA
POPF
RET
retardo_xt: CMP AX,54 ; como máximo 54 ms cada vez
JBE retarda_fin
PUSH AX
MOV AX,54
CALL rt_ax
POP AX
SUB AX,54
JMP retardo_xt
retarda_fin: CALL rt_ax
JMP retardado
rt_ax: MOV DX,1000 ; retardo de hasta 54 ms
MUL DX
MUL CS:tbase
MOV CX,54925
DIV CX ; AX = contador iteraciones
MOV CX,AX
EVEN ; forzar alineamiento
retarda: DEC CX
JMP SHORT $+2
JNZ retarda
RET
retardo ENDP
EVEN
ini_buffer EQU $ ; comienzo del buffer E/S
fin_residente EQU $ ; fin del área residente sin contar el buffer
bytes_resid EQU fin_residente-ini_residente
; ****************************************************************
; * *
; * I N S T A L A C I O N D E S D E E L C O N F I G *
; * *
; ****************************************************************
init PROC
LEA DX,retorno_ok
MOV CS:p_rutinas,DX ; anular 'init'
LES BP,[BX].bpb_cmd ; apuntar a los parámetros
LEA AX,bpb_ptrs
MOV [BX].bpb_cmd_desp,AX
MOV [BX].bpb_cmd_segm,CS ; tabla punteros a BPB's
XPUSH <DS, BX>
PUSH CS
POP DS ; DS: -> _PRINCIPAL
MOV BX,BP
CALL salta_nombre
LEA BP,parametros
CALL obtener_param
CALL testAT
JC init_m1 ; en PC/XT, siempre DMA
CMP param_nodma,OFF
JE init_m1
MOV modoDMA,OFF ; en AT, permitir NO-DMA
init_m1: CALL inic_general
CMP param_b,ON
JNE init_m2
MOV AX,tpista ; /B permite modificar el
MOV tbuffer,AX ; tamaño del buffer
init_m2: CALL inic_ioctl
MOV AL,num_discos
XPOP <BX, DS>
MOV [BX].num_disc_init,AL
MOV AH,[BX].nuevo_disco ; unidad en DOS 3.0+
XPUSH <CS, CS>
XPOP <DS, ES> ; DS y ES: -> _PRINCIPAL
TEST error,0FFFFh
JZ cont_instala1
JMP salida_error
cont_instala1: MOV unidad_base,AH
CALL genera_nombre ; de AL unidades desde AH
CALL analiza_equipo ; ¿ordenador adecuado?
TEST error,0FFFFh
JZ cont_instala2
JMP salida_error
cont_instala2: CMP instalado,ON
JNE cont_instala3
OR error,YAINST
JMP salida_error
cont_instala3: CALL mx_get_handle ; obtener código Multiplex
JNC handle_ok
OR error,MX64FULL ; no quedan entradas
JMP salida_error
handle_ok: MOV multiplex_id,AH ; entrada multiplex
CALL preservar_ints ; tomar nota de vectores
LEA BX,ini_buffer+15
MOV CL,4
SHR BX,CL
MOV AX,CS
ADD AX,BX
MOV sbuffer,AX
MOV sbuf512,AX
CMP param_nodma,ON
JNE usar_dma ; DMA usado
CMP param_ems,ON
JNE init_tsr
CALL alloc_EMS ; poner buffer en EMS
JMP init_tsr
usar_dma: MOV BX,tbuffer
CALL getdmaok
AND BX,BX
JZ dmaguay ; no hay problemas de DMA
MOV sbuffer,AX ; arreglar cruce frontera
MOV sbuf512,AX
ADD tbuffer,BX
OR error,DMACRUCE ; ¡maldita frontera!
dmaguay: CALL vds_dma_ok?
MOV emmtipo,BX ; tipo de EMM
JNC init_tsr
OR error,DMAPOCO ; poco buffer DMA en EMM
init_tsr: CALL inicializa_id
MOV DI,100h ; ORG 0 (compensar COM)
CALL activar_ints ; interceptar vectores
LEA DX,programa_txt ; mensaje de instalación
CALL print
LEA DX,instalado_txt
CALL print
CMP pcxt,ON
JNE ins_at
CMP param_nodma,OFF
JE ins_at
LEA DX,errxtdma_txt ; PC/XT necesita DMA
CALL print
ins_at: TEST error,DMACRUCE
JZ buffernormal
LEA DX,dma_front_txt
CALL print ; aviso de frontera DMA
buffernormal: TEST error,DMAPOCO
JZ bastantedma
LEA DX,dma_poco_txt
CALL print ; aviso de poco buffer DMA
CMP emmtipo,"QE"
LEA DX,crlf_txt
JNE pr_emm
LEA DX,emm_qemm_txt
pr_emm: CALL print ; informar de QEMM
bastantedma: CMP param_ems,ON
JNE ems_ok
CMP ems_handle,0
JNE ems_ok
LEA DX,erremsins_txt
CMP param_nodma,ON
JE err_ems_ok
LEA DX,erremsdma_txt
err_ems_ok: CALL print
ems_ok: MOV AX,longitud_total
MOV CL,4
SHL AX,CL
LDS BX,CS:pcab_peticion
MOV [BX].fin_resid_desp,AX
MOV [BX].fin_resid_segm,CS
MOV AX,100h ; instalación Ok.
RET
salida_error: LEA DX,programa_txt
CALL print
LEA DX,mal_dos_txt ; errores posibles
TEST error,MALDOS ; desde el CONFIG
JNZ prn_error
LEA DX,mal_bios_txt
TEST error,MALBIOS
JNZ prn_error
LEA DX,mal_drv_txt
TEST error,MALDRV
JNZ prn_error
LEA DX,err_sintax_txt
TEST error,ERRSINTAX ; ¿error de sintaxis?
JNZ prn_error
LEA DX,nocabe_txt
TEST error,MX64FULL
JNZ prn_error
LEA DX,ya_ins_txt
prn_error: CALL print ; imprimir error
LDS BX,CS:pcab_peticion
MOV [BX].fin_resid_desp,0 ; OFFSET 0 indica que no
MOV [BX].fin_resid_segm,CS ; quedará instalado
MOV AX,100h ; indicar retorno correcto
RET
init ENDP
; ********************************************************************
; * *
; * C O D I G O E J E C U T A D O D E S D E E L D O S *
; * *
; ********************************************************************
main PROC FAR
MOV BX,_PILA
SUB BX,_PRINCIPAL ; tamaño de este programa
ADD BX,tampila/16+17 ; más pila y más PSP
MOV AH,4Ah ; cambiar memoria asignada
INT 21h
MOV AX,_PRINCIPAL ; programa de un segmento
MOV DS,AX ; DS: -> _PRINCIPAL
LEA BP,parametros
MOV BX,81h
MOV psp,ES ; anotar PSP
CALL obtener_param ; procesar parámetros
PUSH DS
POP ES ; ES: -> _PRINCIPAL
JNC test_pmts
JMP informar ; error/ayuda
test_pmts: CMP param_nodma,ON
JNE cont_ins
CMP param_test,ON
JE cont_ins
pmt_config: OR error,PARAMCONFIG ; parámetro del CONFIG.SYS
JMP informar
cont_ins: CMP param_ems,ON
JE pmt_config
CALL null_param?
JNE proceder
CALL analiza_equipo
CMP instalado,ON
JNE ayudar ; no instalado y sin parámetros
CALL adaptar_param ; parámetros en copia residente
CALL informe ; informe de unidades/opciones
JMP fin
ayudar: MOV param_ayuda,ON
JMP informar ; no indicados parámetros
proceder: CALL inic_general
CALL analiza_equipo
TEST error,0FFFFh XOR MALDRV
JNZ informar ; error != MALDRV
CALL adaptar_param ; parámetros en copia residente
CMP param_test,ON
JE testear
CMP instalado,ON
JE ya_reside
OR error,NOINST ; programa no instalado
JMP informar ; (obligarlo para formatear)
ya_reside: CALL setbuffer
JC informar
MOV AL,maxpistas
CMP frontera,AL
JBE fr_ok
MOV frontera,AL ; limitar alcance frontera
fr_ok: CALL format_disk
JMP fin
testear: CALL setbuffer
JC informar
CALL test_disk ; calcular mayor capacidad
JMP fin
informar: CALL info
MOV AX,error
fin: MOV AH,4Ch
INT 21h ; final
main ENDP
;*********************************************************
;* *
;* SUBRUTINAS DE PROPOSITO GENERAL PARA LA INSTALACION *
;* *
;*********************************************************
INCLUDE 2MUTIL.INC
; ------------ Saltar nombre del driver en línea de órdenes del CONFIG
salta_nombre PROC
MOV AL,ES:[BX]
INC BX
CMP AL,' '
JE fin_nombre
CMP AL,9
JE fin_nombre
CMP AL,0Dh
JE fin_nombre
CMP AL,0Ah
JE fin_nombre
AND AL,AL
JZ fin_nombre
JMP salta_nombre
fin_nombre: RET
salta_nombre ENDP
; ------------ Nombrar las unidades (AL) a partir de la número AH.
genera_nombre PROC
MOV CL,AL
MOV CH,0 ; CX = nº unidades
MOV AL,AH
ADD AL,'A'
MOV AH,':'
LEA SI,tabla_letras1
LEA DI,tabla_letras2
init_nombres: MOV [SI],AX
MOV [DI],AX
ADD SI,3
ADD DI,3
INC AL
LOOP init_nombres
RET
genera_nombre ENDP
; ------------ Inicializar ciertas variables.
inic_general PROC
CALL testDRDOS
CALL testAT
JNC skip_tmtest ; en AT no calcularlo [*]
CALL cte_tiempos
MOV tbase,AX ; cte. retardo para 1/18,2 seg.
skip_tmtest:
MOV num_discos,0
MOV DL,0
CALL tipo_disco
JNC hay_unidad
MOV DL,1
CALL tipo_disco
JNC hay_unidad
OR error,MALBIOS ; no hay disqueteras
RET
hay_unidad: MOV disco,0
MOV DL,disco
CALL tipo_disco
CMP BL,2
JE tipoE_HD
CMP BL,4
JAE tipoE_HD ; hallada A: de alta densidad
INC disco
MOV DL,disco
CALL tipo_disco
CMP BL,2
JE tipoE_HD
CMP BL,4
JAE tipoE_HD ; hallada B: de alta densidad
OR error,MALDRV
RET
tipoE_HD: MOV info_E.tipo_drv,BL ; guardar tipo unidad
MOV AL,disco
MOV info_E.unidad,AL ; y si es la A: ó B:
ADD info_E.ioctl_id,AL
INC num_discos ; de momento, 1 unidad
CMP AL,1
JE fin_inic ; procesadas A: y B:
MOV DL,1
CALL tipo_disco
CMP BL,2
JE tipoF_HD
CMP BL,4
JB fin_inic ; hallada B: de alta densidad
tipoF_HD: MOV info_F.tipo_drv,BL ; guardar tipo unidad
MOV info_F.unidad,1 ; y que es la B:
ADD info_F.ioctl_id,1
INC num_discos ; 2 unidades controladas
fin_inic: MOV AX,m_35_ed ; buffer para 2.88M
CMP info_E.tipo_drv,5
JAE inic_buff
CMP info_F.tipo_drv,5
JAE inic_buff
MOV AX,m_35_hd ; buffer para 1.44M
CMP info_E.tipo_drv,4
JE inic_buff
CMP info_F.tipo_drv,4
JE inic_buff
MOV AX,m_525_hd ; buffer para 1.2M
inic_buff: MOV tbuffer,AX
RET
inic_general ENDP
; --- Comprobar si es DR-DOS 6.0 ó Novell DOS 7.0
testDRDOS PROC
MOV AX,4452h
INT 21h
JC drdos_tst
CMP AL,67h
JB drdos_tst
MOV drdos6,ON ; DR-DOS 6 / Novell DOS 7
drdos_tst: RET
testDRDOS ENDP
; ------------ Inicializar la información IOCTL de las unidades.
; Se asume que sólo DS apunta a los datos.
inic_ioctl PROC
PUSH ES ; *
PUSH DS
POP ES
LEA DI,info_E
CALL inic_ioct_DI
LEA DI,info_F
CALL inic_ioct_DI
POP ES ; *
RET
inic_ioct_DI: MOV AL,[DI].tipo_drv
LEA SI,info_drv288
CMP AL,5
JAE info_drv_ok
LEA SI,info_drv120
CMP AL,2
JE info_drv_ok
LEA SI,info_drv144
info_drv_ok: MOV CX,6
CLD
REP MOVSB
INC SI ; respetar byte tipo soporte
INC DI
MOV CX,31
REP MOVSB
RET
inic_ioctl ENDP
; ------------ Comprobar que la configuración es la adecuada.
analiza_equipo PROC
CALL residente?
MOV AL,OFF
JC set_resid
MOV AL,ON
set_resid: MOV instalado,AL
MOV AH,30h
INT 21h
XCHG AH,AL
CMP AX,31Eh ; ¿DOS 3.30 o superior?
MOV AX,MALDOS
JB pc_nok
CALL testAT
MOV pcxt,OFF
JNC pc_ok
MOV pcxt,ON
JMP pc_ok
pc_nok: OR error,AX
pc_ok: RET
analiza_equipo ENDP
; ----- Detectar 286 ó superior.
testAT PROC
PUSHF
POP AX
OR AH,70h ; intentar activar bit 12, 13 ó 14
PUSH AX ; del registro de estado
POPF
PUSHF
POP AX
AND AH,0F0h
CMP AH,0F0h
JE testedAT
STC
testedAT: CMC ; CF = 0 en AT y 1 en PC/XT
RET
testAT ENDP
; ------------ Comprobar si es un 386+
es386? PROC
PUSHF
POP AX
OR AH,70h ; intentar activar bit 12, 13 ó 14
PUSH AX ; del registro de estado
POPF
PUSHF
POP AX
AND AH,0F0h
CMP AH,0F0h
MOV AL,0
JE fin_test_CPU ; es 8086 o similar
AND AH,70h ; 286 pone bits 12, 13 y 14 a cero
JZ fin_test_CPU ; es 286
MOV AL,1 ; 386 o superior
fin_test_CPU: MOV AH,0
CMP AX,1
RET
es386? ENDP
; ------------ Calcular la constante de retardo básica para perder
; exactamente 54,925 ms. Con una regla de 3 se podrá
; después aplicar para hacer retardos de milisegundos
; en los PC/XT.
cte_tiempos PROC
XPUSH <DS, ES, BX, CX, DX>
MOV AX,3508h
INT 21h
XPUSH <ES, BX> ; preservar vector de INT 8
PUSH DS
MOV AX,40h
MOV DS,AX
MOV AL,DS:[6Ch]
espera_i8: CMP AL,DS:[6Ch]
JE espera_i8 ; esperar INT 8 ... para que no
POP DS
LEA DX,i8_crono ; venga otra en un buen rato...
MOV AX,2508h
INT 21h ; nueva rutina de INT 8
IN AL,21h
PUSH AX ; preservar estado de IRQ's
MOV AL,11111110b
OUT 21h,AL ; permitir sólo IRQ0
MOV AH,0 ; fase
MOV CX,0 ; contador
MOV BX,CX ; seguiría a 0 si fallara
EVEN ; forzar alineamiento
cuenta_iter: DEC CX ; <─┐ bucle básico de retardo
JMP SHORT $+2 ; │
JNZ cuenta_iter ; <─┘ lo interrumpirá INT 8
POP AX ; anterior estado de IRQ's
OUT 21h,AL
XPOP <DX, DS>
PUSH BX ; valor real contado
MOV AX,2508h ; restaurar vector de INT 8
INT 21h
POP AX ; (65536-AX) vueltas en 54,9 ms
NEG AX ; constante de retardo básica
XPOP <DX, CX, BX, ES, DS>
RET
i8_crono: INC AH ; nueva INT 8 que interrumpe
CMP AH,1 ; el bucle de retardo
JE fase1
CMP AH,2
JE fase2
i8_exit: MOV AL,20h
OUT 20h,AL
IRET
fase1: MOV CX,0 ; sincronizar con el reloj
JMP i8_exit
fase2: MOV BX,CX ; anotar constante de retardo
MOV CX,1 ; forzar fin del bucle
JMP i8_exit
cte_tiempos ENDP
; ------------ Inicializar área «program_id» del programa residente.
inicializa_id PROC
MOV segmento_real,CS ; anotar segmento del bloque
MOV offset_real,0 ; ídem con el offset
MOV AX,bytes_resid ; tamaño área residente
ADD AX,tbuffer ; tamaño buffer residente
ADD AX,31 ; redondeo (programa+buffer)
CMP ems_handle,0
JE mem_AX
MOV AX,bytes_resid ; tamaño área residente
ADD AX,512+SYSBYTES+GAPDEF+31 ; minibuffer+redondeo
mem_AX: MOV CL,4
SHR AX,CL
MOV longitud_total,AX
OR info_extra,3 ; SYS en formato EXE
RET
inicializa_id ENDP
; ------------ Ubicar el buffer interno en EMS.
alloc_EMS PROC
PUSH ES
MOV AX,3567h
INT 21h ; vector de INT 67h en ES:BX
MOV DI,10
LEA SI,emm_id
MOV CX,8
CLD
REP CMPSB ; ¿instalado controlador EMS?
POP ES
JE hay_emm
JMP finprep_emm
hay_emm: MOV CX,8000h ; nº de intentos prudente
emm_llama: MOV AH,40h
INT 67h
AND AH,AH
JZ emm_responde
CMP AH,82h
LOOPE emm_llama
JMP finprep_emm ; no funciona ¿?
emm_responde: MOV AH,41h
INT 67h
AND AH,AH
JZ emm_pag_ok
CMP AH,82h
JE emm_responde ; reintentar (EMM ocupado)
JMP finprep_emm
emm_pag_ok: MOV marco_ems,BX ; inicializar marco EMS
MOV AH,46h
INT 67h ; obtener versión del EMM
CMP AL,40h
JB emm_obt_kb ; versión anterior a la 4.0
MOV ems4,ON
emm_obt_pag: XPUSH <ES,DS>
POP ES
MOV AX,5800h ; obtener dirección de páginas
LEA DI,buffer_aux
INT 67h
POP ES
AND AH,AH
JZ emm_pags_ok
CMP AH,82h
JE emm_obt_pag
JMP finprep_emm
emm_pags_ok: LEA SI,buffer_aux
CLD
emm_otra_pag: LODSW
MOV BX,AX ; BX = segmento de la página
LODSW ; AX = nº de la página
AND AX,AX
JE hallada_pag0 ; encontrada página 0
LOOP emm_otra_pag
JMP finprep_emm
hallada_pag0: LODSW ; segmento página 1
SUB AX,BX
CMP AX,1024 ; ¿(pag1 - pag0) != 1024?
JNE finprep_emm ; páginas no contiguas
LODSW
LODSW ; segmento página 2
SUB AX,BX
CMP AX,2048 ; ¿(pag2 - pag0) != 2048?
JNE finprep_emm ; páginas no contiguas
LODSW
LODSW ; segmento página 3
SUB AX,BX
CMP AX,3072 ; ¿(pag3 - pag0) != 3072?
JNE finprep_emm ; páginas no contiguas
emm_obt_kb: MOV BX,tbuffer
ADD BX,16383 ; BXi = redondeo
ROL BX,1
ROL BX,1
AND BX,3 ; BX = BXi / 16384
MOV AH,43h
INT 67h
AND AH,AH
JZ ems_alloc_ok
CMP AH,82h
JE emm_obt_kb ; reintentar (EMM ocupado)
JMP finprep_emm
ems_alloc_ok: MOV ems_handle,DX
CMP ems4,ON
JNE finprep_emm
MOV AX,5301h
LEA SI,emm_nombre
INT 67h
finprep_emm: RET
alloc_ems ENDP
; ------------ Devolver ZF=1 si no se indica ningún parámetro.
null_param? PROC
MOV AH,param_ayuda
OR AH,param_dd
OR AH,param_dh
OR AH,param_ed
OR AH,param_k
OR AH,param_n
OR AH,param_test
OR AH,param_t
OR AH,param_r
OR AH,param_s
OR AH,param_f
OR AH,param_b
OR AH,param_x
OR AH,param_y
OR AH,param_m
NOT AH
MOV AL,disquetera
XOR AX,ptr_label
XOR AX,ptr_ilabel
CMP AX,-1
RET
null_param? ENDP
; ------------ Informar al usuario.
info PROC
CMP param_ayuda,ON ; ¿solicitud de ayuda?
JNE info_normal
LEA DX,ayuda_txt
CALL print
JNC fin_info
LEA DX,limpia_txt ; se pulsó ESC en la ayuda
CALL print
JMP fin_info
info_normal: LEA DX,programa_txt
CALL print
LEA DX,mal_dos_txt
TEST error,MALDOS ; ¿DOS incorrecto?
JZ otroerr2
CALL print
otroerr2: LEA DX,mal_bios_txt
TEST error,MALBIOS ; ¿BIOS obsoleta?
JZ otroerr3
CALL print
otroerr3: LEA DX,err_sintax_txt
TEST error,ERRSINTAX ; ¿error de sintaxis?
JZ otroerr4
CALL print
LEA DX,pet_ayuda_txt
CALL print
otroerr4: LEA DX,no_ins_txt
TEST error,NOINST ; ¿no instalado en CONFIG?
JZ otroerr5
CALL print
otroerr5: LEA DX,err_mem_txt
TEST error,POCAMEM ; ¿poca memoria?
JZ otroerr6
CALL print
otroerr6: LEA DX,pconfig_txt
TEST error,PARAMCONFIG ; ¿parámetro del CONFIG?
JZ fin_info
CALL print
fin_info: RET
info ENDP
; ------------ Establecer el buffer que no cruce con el DMA.
setbuffer PROC
MOV AH,48h
MOV BX,MPISTA*2/16
INT 21h
JNC haymem
OR error,POCAMEM
STC
RET
haymem: MOV BX,MPISTA ; mayor buffer posible
CALL getdmaok ; AX = segmento no conflictivo
MOV sbuffer,AX
MOV sbuf512,AX
CLC
RET
setbuffer ENDP
; ------------ Obtener un segmento no conflictivo con el DMA. A la
; entrada, AX=segmento propuesto y BX=tamaño buffer en
; bytes. A la salida, AX podría haber sido incrementado
; y BX indicaría en cuántos bytes.
getdmaok PROC
XPUSH <CX, DX>
SHR BX,1
SHR BX,1
SHR BX,1
SHR BX,1 ; bytes tamaño -> párrafos
MOV CX,AX
MOV DX,BX
ADD DX,AX ; DX = segmento final
AND DH,0F0h ; página del segmento final
AND CH,0F0h ; página del segmento inicial
MOV BX,0 ; supuesto ajuste nulo
CMP CH,DH
JE buff_ok ; no hay problemas con DMA
MOV DL,0 ; DX = nuevo segmento
MOV BX,DX
SUB BX,AX ; incremento relativo
MOV AX,DX
buff_ok: MOV CL,4
SHL BX,CL ; incremento relativo en bytes
XPOP <DX, CX>
RET
getdmaok ENDP
; ------------ Comprobar si el buffer para el DMA es suficiente, en
; caso de haber un controlador de memoria. Se devuelve
; el código de identificación del controlador en BX, o
; un valor 1234h si no hay controlador; DI indica el
; tamaño de buffer soportado y CF=1 si no basta.
vds_dma_ok? PROC
XPUSH <AX, CX, DX, SI>
CALL es386?
JNE vds_pse ; por si las moscas
MOV AX,354Bh
PUSH ES
INT 21h ; ES:BX -> INT 4Bh
MOV AX,ES
POP ES
OR AX,BX
JZ vds_pse ; INT 4Bh indefinida
CMP AX,0FFFFh
JNE hay_vds?
CMP BX,0FFFFh
JE vds_pse ; INT 4Bh indefinida
hay_vds?: MOV AX,8102h
XOR DX,DX
XOR SI,SI
XOR DI,DI ; SI:DI a 0 por si acaso
INT 4Bh
JC vds_pse ; si no hay VDS...
MOV AX,SI
OR AX,DI
JZ vds_pse ; no parece una VDS...
CMP SI,0
JE dma_s_ok
MOV DI,0FFFFh ; con 64K nos basta
dma_s_ok: CMP DI,tbuffer
JAE vds_ok
STC ; no basta el buffer
XPOP <SI, DX, CX, AX>
RET
vds_pse: MOV BX,1234h ; retornar sin problemas
MOV DI,0FFFFh
vds_ok: CLC ; basta ese buffer
XPOP <SI, DX, CX, AX>
RET
vds_dma_ok? ENDP
; ------------ Adaptar parámetros del programa si ya está instalado.
adaptar_param PROC
PUSH ES
CMP instalado,ON
JNE salir_adap ; aún no instalado
MOV ES,tsr_seg
CMP param_g,ON
JNE param_dr?
MOV AX,gaprw
MOV ES:gaprw,AX
param_dr?: CMP param_dron,ON
JNE param_droff?
MOV ES:drdos6,ON ; soporte DISKCOPY de DR-DOS
param_droff?: CMP param_droff,ON
JNE param_dwon?
MOV ES:drdos6,OFF
param_dwon?: CMP param_dwon,ON
JNE param_dwoff?
MOV ES:cachewr,ON ; caché escritura retardada
param_dwoff?: CMP param_dwoff,ON
JNE fin_adap
MOV ES:cachewr,OFF
fin_adap: MOV AX,tbase
MOV ES:tbase,AX ; actualizar siempre esta cte
salir_adap: POP ES
RET
adaptar_param ENDP
; ------------ Informar de las unidades empleadas y otras cuestiones.
informe PROC
PUSH ES
MOV ES,tsr_seg
MOV AL,ES:unidad_base ; primera letra unidad
MOV BL,ES:info_E.unidad
MOV BH,ES:info_E.tipo_drv ; datos A:
MOV CL,ES:info_F.unidad
MOV CH,ES:info_F.tipo_drv ; datos B:
POP ES
LEA DX,hay_2mgui_txt
CALL print
MOV nueva_u,AL
ADD nueva_u,'A'
informa_otra: MOV vieja_u,BL
ADD vieja_u,'A'
LEA DX,hay_en_txt
CALL print
LEA DX,nueva_u ; indicar nueva unidad
CALL print
MOV BL,BH
DEC BL
MOV BH,0
SHL BX,1
ADD BX,OFFSET t_drvs
MOV DX,[BX]
CALL print ; imprimir su tipo
LEA DX,hay2_txt
CALL print
LEA DX,vieja_u
CALL print ; imprimir letra física
AND CH,CH
JZ fin_informe ; no hay más unidades
MOV BX,CX
MOV CH,0
INC nueva_u
JMP informa_otra ; informar 2ª unidad
fin_informe: PUSH ES ; *
MOV ES,tsr_seg
LEA DX,gap_txt
CALL print
MOV AX,ES:gaprw
XOR DX,DX
MOV CL,3
CALL print_32 ; indicar el GAP
LEA DX,dma1_txt
CALL print
CMP ES:modoDMA,ON
JE modo_dma_ok
LEA DX,dmano_txt
CALL print
modo_dma_ok: LEA DX,dma2_txt
CALL print ; y el modo DMA
CMP ES:ems_handle,0
LEA DX,buffer_ems_txt
JE modo_ems_ok
CALL print
modo_ems_ok: LEA DX,cache_off_txt
CMP ES:cachewr,ON
JE modo_cache_ok
CALL print
modo_cache_ok: LEA DX,sopdr_on_txt
CMP ES:drdos6,ON
JNE modo_dr_ok
CALL print
modo_dr_ok: POP ES ; *
LEA DX,pet_ayuda_txt
CALL print ; ... cómo pedir ayuda ...
RET
informe ENDP
; ------------ Formatear disquete 2MGUI.
format_disk PROC
CALL get_drv ; obtener unidad física
JNC fmt_buen_drv
OR errw,MALDRV
JMP rep_fmt
fmt_buen_drv: CALL init_flp ; preparar áreas de datos
CALL init_boot ; construir sector de arranque
CALL set_fat_buffer ; buffer para la FAT
JNC fmt_buena_fat
JMP rep_fmt ; no hay memoria para la FAT
fmt_buena_fat: MOV errw,0
MOV status,0 ; borrar errores previos
CALL print_cabf ; mensaje de cabecera
CMP param_k,ON
JE format_ya ; opción /K: evitar pausa
LEA DX,pausaf_txt
CALL print
MOV AH,8
INT 21h ; pedir tecla
AND AL,AL
JNZ esa_tec
MOV AH,8
INT 21h ; tecla de doble código
esa_tec: LEA DX,limpia_txt
CALL print
CMP AL,13
JE format_ya
JMP teclaESC? ; se pulsó ESC
format_ya: STC
CALL reset_drv
MOV [SI].cilindro,0
fmt_otro_cil: MOV [SI].cabezal,0 ; empezar en pista/cabeza 0
fmt_otro_cab: MOV CX,4 ; reintentos
JMP fmt_empieza
fmt_repite: CLC
CALL reset_drv
fmt_empieza: CALL test_kb
JNC fmt_proc
JMP teclaESC?
fmt_proc: CALL print_cc ; imprimir nº cilindro/cabezal
CALL genera_infof
CALL motor_ok
CALL seek_drv
LEA DX,f_txt ; [F--]
CALL print
CALL formatea_pista
CALL test_err ; ¿error?
JNC fmt_wr?
JMP rep_fmt
fmt_wr?: JNZ fmt_wr
LOOP fmt_repite ; reintentos
JMP marca_pista ; pista defectuosa
fmt_wr: CMP [SI].cilindro,1
CMC
CALL init_buffer ; buffer a 0 en cilindro 0
LEA DX,w_txt
CALL print ; [-X-]
CALL escribe_pista
CALL fix_err ; detectar capacidad excesiva
CALL test_err ; ¿error?
JC rep_fmt
JNZ fmt_vr
LOOP fmt_repite ; reintentos
JMP marca_pista ; pista defectuosa
fmt_vr: CMP [SI].cilindro,2
JB si_verificar ; verificar siempre pistas 0-1
CMP param_n,ON
JE fmt_inc_cab ; verificación desactivada
si_verificar: CALL test_kb
JC teclaESC?
LEA DX,v_txt
CALL print ; [--V]
CALL lee_pista
CALL fix_err ; detectar capacidad excesiva
CALL test_err ; ¿error?
JC rep_fmt
JNZ fmt_inc_cab
LOOP fmt_repite
JMP marca_pista ; pista defectuosa
fmt_inc_cab: INC [SI].cabezal
CMP [SI].cabezal,1
JA fmt_inc_cil
JMP fmt_otro_cab ; a por otro cabezal...
fmt_inc_cil: INC [SI].cilindro
MOV AL,[SI].cilindro
CMP AL,2
JB fmt_lento
CMP param_q,ON
JE fin_fmt ; opción /Q
fmt_lento: CMP AL,maxpistas
JAE fin_fmt
JMP fmt_otro_cil ; a por otro cilindro ...
teclaESC?: CMP AX,1000h
JE fin_fmt ; Quickformat
OR errw,ABORTADO
JMP rep_fmt
marca_pista: CMP [SI].cilindro,0 ; ¿no puede ni con la primera?
JE rep_fmt ; mal asunto, es la del sistema
CALL marcar_fat
JMP fmt_inc_cab ; marcar esa pista y a por otra
fin_fmt: CALL init_disk
rep_fmt: CLC
CALL motor_off_cnt ; cuenta normal detención motor
CALL info_fmt
TEST errw,MALDRV OR MUCHAFAT OR ABORTADO
JNZ format_fin ; fin total del proceso
CMP param_k,ON
JE format_fin ; con /K sólo un disco
JMP format_disk ; formatear más discos
format_fin: RET
format_disk ENDP
; ------------ Comprobar si se pulsa ESC y limpiar buffer.
test_kb PROC
MOV AH,1
INT 16h
JZ no_ESC ; no quedan teclas en el buffer
MOV AH,0
INT 16h
CMP AL,27
JE si_ESC ; tecla ESC
CMP AX,1000h
JE si_ESC ; ALT-Q
JMP test_kb
si_ESC: STC
RET
no_ESC: CLC
RET
test_kb ENDP
; ------------ Si da error de unidad no preparada al escribir o al
; verificar en la primera pista y no lo dio al formatear,
; es que se pide más capacidad de la soportada.
fix_err PROC
TEST status,80h
JZ fix_err_r
CMP [SI].cilindro,0
JNE fix_err_r ; si no es cilindro 0, vale
MOV status,7Fh
fix_err_r: RET
fix_err ENDP
; ------------ Comprobar categoría del error. Los errores fatales
; provocan el final inmediato del formateo.
test_err PROC
CMP status,0
JE err_none
CMP status,3 ; ¿protegido contra escritura?
JE err_fatal
TEST status,80h ; ¿no preparada?
JNZ err_fatal
CMP SP,SP
CLC
RET ; ZF=1 y CF=0 -> error "venial"
err_none: CMP SP,0
CLC
RET ; ZF=0 y CF=0 -> sin error
err_fatal: CMP SP,SP
STC
RET ; ZF=1 y CF=1 -> error grave
test_err ENDP
; ------------ Poner el buffer de pista con valores de test. A la
; entrada, CF=0 selecciona un buffer lleno de ceros
; y CF=1 lleno de una secuencia aleatoria predecible.
init_buffer PROC
PUSH ES
XPUSH <AX, BX, CX>
MOV ES,sbuffer
MOV BX,0
JC buffer_rnd
CALL tpistaAX
MOV CX,AX
fill_pis0: MOV BYTE PTR ES:[BX],0
INC BX
LOOP fill_pis0 ; buffer a 0
JMP buff_init
buffer_rnd: CALL tpistaAX
MOV CX,AX
MOV semilla,1 ; nº aleatorios predecibles
fill_pisx: CALL rnd
MOV BYTE PTR ES:[BX],AL
INC BX
LOOP fill_pisx ; buffer con patrón aleatorio
buff_init: XPOP <CX, BX, AX>
POP ES
RET
init_buffer ENDP
; ------------ Imprimir cabecera de formateo.
print_cabf PROC
XPUSHA
LEA DX,fmtm1_txt
CALL print ; "Formateando ..."
MOV AL,[SI].infb.mfrontera
MOV AH,0
MUL [SI].infb.tpista1
MOV BX,DX
MOV CX,AX ; BX:CX bytes hasta FRONTERA
MOV AL,maxpistas
SUB AL,[SI].infb.mfrontera
MOV AH,0
MUL [SI].infb.tpista2 ; DX:AX bytes tras FRONTERA
ADD AX,CX
ADC DX,BX ; bytes totales por cara
MOV CL,maxpistas
MOV CH,0
DIV CX ; bytes por pista
XOR DX,DX
MOV CL,7+16
PUSH AX ; *
CALL print_32 ; imprimir bytes por pista
LEA DX,fmtm2_txt
CALL print
MOV DL,disquetera
ADD DL,'A'
MOV AH,2
INT 21h ; imprimir unidad
LEA DX,fmtm3_txt
CALL print
MOV DL,[SI].unidad
CALL tipo_disco ; tipo de la unidad
DEC BL
MOV BH,0
SHL BX,1
ADD BX,OFFSET t_drvs
MOV DX,[BX]
CALL print ; imprimir tipo
LEA DX,fmtm4_txt
CALL print
LEA DX,fmtm5_txt
CALL print
CALL print_dsk_tipo ; imprimir tipo del disquete
LEA DX,fmtm6_txt
CALL print
POP AX ; * bytes por pista
MOV BL,maxpistas
MOV BH,0
SHL BX,1 ; pore las dos caras
MUL BX ; DX:AX bytes en disco
MOV BX,1024
DIV BX ; AX Kbytes
XOR DX,DX
MOV CL,6+16
CALL print_32 ; imprimir Kbytes
LEA DX,fmtm7_txt
CALL print
XPOPA
RET
print_cabf ENDP
; ------------ Imprimir el tipo del disquete en uso.
print_dsk_tipo PROC
MOV DL,[SI].unidad
CALL tipo_disco ; tipo de la unidad
MOV BH,BL
CMP BL,5
JB ted_no
MOV BL,4 ; en 2.88M por defecto 1.44M
ted_no: MOV AL,param_dd
OR AL,param_dh
CMP AL,OFF
JE tdd_ok
DEC BL ; disco DD
tdd_ok: CMP param_ed,ON
JNE ted_ok
CMP BH,5
JNE ted_ok
MOV BL,5 ; disco 2.88M
ted_ok: DEC BL
MOV BH,0
SHL BX,1
ADD BX,OFFSET t_drvs
MOV DX,[BX]
CALL print ; imprimir tipo
RET
print_dsk_tipo ENDP
; ------------ Imprimir nº cilindro y cabezal.
print_cc PROC
XPUSHA
LEA DX,cil_txt
CALL print
MOV AL,[SI].cilindro
CALL print_8
LEA DX,cab_txt
CALL print
MOV AL,[SI].cabezal
CALL print_8
LEA DX,p_txt
CALL print
XPOPA
RET
print_cc ENDP
; ------------ Establecer buffer para la FAT.
set_fat_buffer PROC
MOV AX,fbuffer
AND AX,AX
JNZ haymemfat ; ya había memoria asignada
MOV AX,bsectfat
MOV BX,[SI].bytes_sector
MUL BX ; sectfat * tamaño sector
MOV CL,4
SHR AX,CL ; bytes -> párrafos
MOV BX,AX
MOV AH,48h
PUSH BX
INT 21h ; pedir memoria
POP BX
JNC haymemfat
OR errw,MUCHAFAT ; no hay memoria suficiente
STC
RET
haymemfat: MOV fbuffer,AX
PUSH ES ; *
MOV ES,AX
XOR DI,DI
MOV AX,bsectfat
MUL [SI].bytes_sector ; sectores -> bytes
SHR AX,1 ; palabras
MOV CX,AX
SUB CX,2 ; saltar dos primeras palabras
MOV AL,media_id
CLD
STOSB ; byte de medios
MOV AX,0FFFFh
STOSW ; otros dos bytes
MOV AL,0
CMP tipofat,12
JE init_fat4
DEC AL
init_fat4: STOSB ; 0 (FAT12) ó 0FFh (FAT16)
XOR AX,AX
REP STOSW ; poner resto de FAT a 0
POP ES ; *
CLC
RET
set_fat_buffer ENDP
; ------------ Marcar pista defectuosa en la FAT.
marcar_fat PROC
MOV AL,[SI].cilindro
SHL AL,1
ADD AL,[SI].cabezal ; AX pistas hasta la frontera
MOV AH,0
MOV CX,0 ; CX pistas desde la frontera
MOV BL,[SI].infb.mfrontera
SHL BL,1
CMP AL,BL
JBE dispis_ok
MOV CL,AL
MOV AL,BL ; hay cruce de frontera
SUB CL,AL
dispis_ok: MUL [SI].infb.tpista1
XPUSH <DX, AX>
MOV AX,CX
MUL [SI].infb.tpista2 ; DX:AX = bytes tras frontera
XPOP <BX, CX> ; CX:BX = bytes antes frontera
ADD AX,BX
ADC DX,CX ; offset al primer byte erróneo
XPUSH <AX, DX>
MOV CX,[SI].bytes_sector
DIV CX
MOV BX,AX ; BX = primer sector erróneo
CALL tpistaAX
MOV CX,AX ; tamaño pista
XPOP <DX, AX>
ADD AX,CX
ADC DX,0
MOV CX,[SI].bytes_sector
DIV CX
AND DX,DX
JZ ultserr_ok
INC AX ; AX = último sector erróneo
ultserr_ok: SUB AX,BX
MOV CL,bscluster
MOV CH,0
ADD AX,CX
DEC AX
XOR DX,DX
DIV CX ; AX = clusters defectuosos
DEC BX ; descontar BOOT
PUSH AX
MOV AX,32
MUL brootdir
DIV [SI].bytes_sector
SUB BX,AX ; descontar ROOT
POP AX
MOV CL,bnfats
MOV CH,0
desc_fat: SUB BX,bsectfat
LOOP desc_fat ; descontar FAT(s)
XCHG AX,BX ; AX=primer sector, BX=nºclusters
XOR DX,DX
MOV CL,bscluster
DIV CX ; AX = primer cluster
ADD AX,2 ; se numeran desde 2
MOV CX,BX
marcar: CALL badpoke_fat ; marcar cluster erróneo
INC AX
LOOP marcar
RET
marcar_fat ENDP
; --- Modificar una entrada en la FAT12 ó 16.
badpoke_fat PROC
XPUSH <DS, AX, BX, CX>
MOV DS,fbuffer
XOR BX,BX
CMP CS:tipofat,16
JE poke_fat16
MOV DX,0FF7h ; cluster defectuoso
CALL poke_fat12
JMP fat_poked
poke_fat16: SHL AX,1
ADD BX,AX
MOV WORD PTR DS:[BX],0FFF7h
fat_poked: XPOP <CX, BX, AX, DS>
RET
badpoke_fat ENDP
; --- Escribir un elemento en una FAT-12
; Entrada: AX = posición de dicho elemento
; DS:BX = FAT cargada en memoria
; DX = nuevo valor de dicho elemento
poke_fat12 PROC
PUSH AX ; preservar registros
PUSH BX
PUSH DX
ADD BX,AX ; BX = BX + cluster
SHR AX,1 ; AX = cluster / 2
PUSHF ; CF = 1 si impar
ADD BX,AX ; BX = BX + cluster * 1,5
MOV AX,[BX] ; AX = palabra con dato 12 bits
POPF
JC poke_fat_imp
AND AX,1111000000000000b ; preservar la otra entrada
JMP poke_fat_ok
poke_fat_imp: AND AX,0000000000001111b ; preservar la otra entrada
PUSH CX
MOV CL,4
SHL DX,CL ; colocarlo: 4 bits a la izda
POP CX
poke_fat_ok: OR AX,DX ; «mezclar»
MOV [BX],AX ; nuevo valor en la FAT
POP DX
POP BX
POP AX
RET ; retorno sin alterar registros
poke_fat12 ENDP
; ------------ Inicializar BOOT y FAT (y ROOT si procede).
init_disk PROC
XPUSHA
MOV [SI].cilindro,0
MOV [SI].cabezal,0
CLC
CALL init_buffer ; buffer a 0
MOV CX,[SI].bytes_sector
XPUSH <ES, SI> ; *
MOV ES,sbuffer
XOR DI,DI
LEA SI,sector_boot
CLD
REP MOVSB ; crear BOOT
XPOP <SI, ES> ; *
CLC
CALL reset_drv
CALL motor_ok
CALL seek_drv
CALL escribe_pista ; grabar a bajo nivel el BOOT
CMP status,0
JNE fallo_init
PUSH ES
MOV ES,tsr_seg
MOV ES:[SI].cambiodisco,ON ; simular cambio de disco
POP ES
MOV DL,disquetera
INC DL
MOV AH,32h
PUSH DS
INT 21h ; forzar acceso a disco usando
POP DS ; ya el sistema operativo
MOV AL,disquetera
XOR BX,BX
MOV CX,bsectfat ; sectores en FAT
MOV DX,1
PUSH DS ; *
MOV DS,fbuffer
CALL int26h ; grabar FAT1
POP DS ; *
JC fallo_init ; fallo al escribir FAT
CMP bnfats,1
JE init_root ; sólo una FAT (CF=0)
XOR BX,BX
MOV CX,bsectfat
MOV DX,CX
INC DX ; saltar FAT1 + BOOT
MOV AL,disquetera
PUSH DS ; *
MOV DS,fbuffer
CALL int26h ; grabar FAT2
POP DS ; *
JNC init_root
fallo_init: OR errw,MALSYS ; fallo en áreas del sistema
JMP fin_init
init_root: MOV BX,ptr_label
AND BX,BX
JNZ tetiq_ok
MOV BX,ptr_ilabel
AND BX,BX
JZ fin_init ; no hay etiqueta de volúmen
tetiq_ok: CLC
CALL init_buffer ; buffer a 0
CALL copia_etiq
CMP BX,ptr_ilabel
JNE wr_root
CALL inc_etiq
wr_root: MOV CX,bsectfat
MOV AL,bnfats
MOV AH,0
MUL CX
INC AX ; primer sector directorio raíz
MOV DX,AX
MOV CX,1
MOV AL,disquetera
PUSH DS ; *
MOV DS,sbuffer
XOR BX,BX
CALL int26h ; grabar ROOT
POP DS
fin_init: XPOPA
RET
init_disk ENDP
; ------------ Como el MS-DOS 7 de Windows 95 (beta 2) no deja usar
; la INT 26h, se graba por IOCTL :-)
int26h PROC
XPUSHA
PUSH ES
MOV ES,ES:tsr_seg
MOV AH,ES:drdos6
MOV ES:drdos6,OFF ; anular emulación DR-DOS
MOV SI,1 ; con caché: CX operaciones
CMP ES:cachewr,ON
MOV SI,CX ; sin caché: una operación
JE nsi26ok
nsi26ok: POP ES
i26_buc: XPUSH <AX, BX, CX, DX, SI, DS> ; * (preservar emulacion)
LEA DI,buffer_aux
MOV BYTE PTR ES:[DI],0
MOV WORD PTR ES:[DI+1],0 ; cabezal
MOV WORD PTR ES:[DI+3],DX ; primer cilindro
MOV WORD PTR ES:[DI+5],0 ; primer sector
MOV WORD PTR ES:[DI+7],SI ; nº sectores
MOV WORD PTR ES:[DI+9],BX
MOV WORD PTR ES:[DI+11],DS ; dirección
INC AX
MOV BL,AL ; unidad
MOV AX,440Dh
MOV CX,841h ; escribir pista
MOV DX,DI
PUSH ES
POP DS
INT 21h
XPOP <DS, SI, DX, CX, BX, AX> ; *
JC i26_fallo
ADD BX,ES:boot_tsect
INC DX
SUB CX,SI
JNZ i26_buc
CLC
i26_fallo: PUSH ES
MOV ES,ES:tsr_seg ; cuidado con flags :-)
MOV ES:drdos6,AH ; restaurar emulación DR-DOS
POP ES
XPOPA
RET
int26h ENDP
; --- Crear etiqueta de volúmen (psp:BX -> sbuffer:0)
copia_etiq PROC
XPUSHA
XPUSH <ES, DS>
CLD
MOV ES,sbuffer
XOR DI,DI
MOV DS,psp
MOV SI,BX
MOV CX,11
JCXZ nom_et_cp
genera_et: LODSB
CMP AL,' '
JE completa_et
CMP AL,9
JE completa_et
CMP AL,'/'
JE completa_et
CMP AL,13
JE completa_et
STOSB
LOOP genera_et
JMP nom_et_cp
completa_et: MOV AL,' '
STOSB
LOOP completa_et
nom_et_cp: MOV BYTE PTR ES:[11],28h
POP DS
MOV WORD PTR ES:[22],2048 ; 1:00
MOV WORD PTR ES:[24],7745 ; 1/2/95
LEA DX,null
MOV AX,3D00h
MOV CX,0
INT 21h ; abrir fichero "NUL"
JC fin_cpet
MOV BX,AX
MOV AX,5700h
PUSH BX
INT 21h ; consultar su fecha/hora
POP BX
JC fin_cpetcf
MOV AX,CX
OR AX,DX
JZ fin_cpetcf
MOV WORD PTR ES:[22],CX ; hora
MOV WORD PTR ES:[24],DX ; fecha
fin_cpetcf: MOV AX,3E00h
INT 21h ; cerrar fichero "NUL"
fin_cpet: POP ES
XPOPA
RET
copia_etiq ENDP
; --- Incrementar nº de etiqueta de volúmen.
inc_etiq PROC
PUSH DS
MOV DS,psp
MOV CX,16
busca_fetq: MOV AL,[BX]
CMP AL,' '
JE fin_etq
CMP AL,9
JE fin_etq
CMP AL,'/'
JE fin_etq
CMP AL,13
JE fin_etq
INC BX
LOOP busca_fetq
JMP etq_inc
fin_etq: DEC BX
MOV AL,[BX]
CMP AL,'0'
JB etq_inc
CMP AL,'9'
JA etq_inc
INC AL
CMP AL,'9'
JA etq_p10
MOV [BX],AL
JMP etq_inc
etq_p10: MOV BYTE PTR [BX],'0'
JMP fin_etq
etq_inc: POP DS
RET
inc_etiq ENDP
; ------------ Inicializar sector de arranque.
init_boot PROC
MOV AL,[SI].infb.vunidad2
MOV bootp.vunidad2,AL
MOV AH,frontera ; disco dividido en dos mitades
CMP AL,[SI].vunidad1
JNE init_fr
MOV AH,maxpistas ; disco uniforme
init_fr: MOV bootp.mfrontera,AH
MOV [SI].infb.mfrontera,AH
MOV AX,bsectini
MOV boot_tsect,AX ; tamaño de sector usado
MOV AX,tcluster
XOR DX,DX
DIV boot_tsect
AND AL,AL
JNZ init_sc
INC AL
init_sc: MOV bscluster,AL ; sectores por cluster
MOV AL,nfats
MOV bnfats,AL ; número de FATs
MOV AX,32
MUL rootdir
DIV boot_tsect
AND DX,DX
JZ bdir_ok
INC AX
bdir_ok: MOV srootdir,AX ; entradas raíz llenando sectores
MUL boot_tsect
MOV CX,32
DIV CX
MOV brootdir,AX ; nº entradas ajustado
MOV AX,[SI].infb.tpista2
MOV bootp.tpista2,AX
MOV AX,[SI].infb.tpista1
MOV bootp.tpista1,AX
MOV BL,bootp.mfrontera
MOV BH,0
SHL BX,1
MUL BX
MOV CX,DX
MOV BX,AX ; CX:BX bytes primera parte disco
MOV AL,maxpistas
SUB AL,[SI].infb.mfrontera
MOV AH,0
SHL AX,1
MUL bootp.tpista2 ; DX:AX bytes segunda parte disco
ADD AX,BX
ADC DX,CX ; DX:AX bytes totales en el disco
DIV boot_tsect
MOV bsectores,AX ; AX = número de sectores
DEC AX ; calcular FAT...
SUB AX,srootdir ; AX = sect tot - 1 boot - N raíz
MOV CX,AX
MOV AL,bscluster
MOV AH,0
SHL AX,1
MUL boot_tsect ; bytes_sect * sect_cluster * 2
MOV BX,3 ; 1.5 * 2 = 3 (FAT12)
DIV BX
ADD AL,bnfats
ADC AH,0
XCHG AX,CX
XOR DX,DX
DIV CX ; AX = sectores ocupados por FAT12
AND DX,DX
JZ f12_ok
INC AX
f12_ok: MOV bsectfat,AX ; sectores en FAT12
MOV tipofat,12 ; supuesta FAT-12
ADD AX,srootdir
INC AX
SUB AX,bsectores ; (fat+root+1) - sectores totales
NEG AX ; resta al revés
XOR DX,DX
MOV CL,bscluster
MOV CH,0
DIV CX ; AX = nº clusters
CMP AX,4085
JB boot_dir ; en efecto, la FAT es de 12
MOV AX,bsectores
DEC AX ; calcular FAT...
SUB AX,srootdir ; AX = sect tot - 1 boot - N raíz
MOV CX,AX
MOV AL,bscluster
MOV AH,0
SHL AX,1
MUL boot_tsect ; bytes_sect * sect_cluster * 2
MOV BX,4 ; 2 * 2 = 4 (FAT16)
DIV BX
ADD AL,bnfats
ADC AH,0
XCHG AX,CX
XOR DX,DX
DIV CX ; AX = sectores ocupados por FAT12
AND DX,DX
JZ f16_ok
INC AX
f16_ok: MOV bsectfat,AX ; sectores en FAT16
MOV tipofat,16
MOV BYTE PTR ftipo+4,'6'
boot_dir: MOV AL,bnfats
MOV AH,0
MUL bsectfat ; sectores ocupados por FATs
INC AX ; más BOOT
ADD AX,srootdir ; más ROOT
SUB AX,bsectores
NEG AX ; sectores totales - ocupados
MOV BL,bscluster
MOV BH,0
XOR DX,DX
DIV BX ; DX = sectores redundantes
MOV AX,boot_tsect
MUL DX
MOV BX,32
DIV BX
ADD brootdir,AX ; aprovecharlos para engordar ROOT
CMP brootdir,240
JBE boot_ok
MOV brootdir,240 ; pero sin pasarse
boot_ok: CALL rnd
MOV WORD PTR bserie,AX ; inicializar nº serie
CALL rnd
MOV WORD PTR bserie+2,AX
RET
init_boot ENDP
; ------------ Informe del formateo.
info_fmt PROC
CALL pr_error ; posible mensaje de error
JNC cont_info_fmt
RET
cont_info_fmt: LEA DX,capacidad1_txt
CALL print
MOV AX,bsectores
MOV CX,[SI].bytes_sector
MUL CX
MOV CL,10+16
CALL print_32 ; capacidad cruda en bytes
LEA DX,capacidad2_txt
CALL print
MOV AX,ptr_label
OR AX,ptr_ilabel
JZ no_etiq
LEA DX,etiq_txt
CALL print
MOV CX,11
XOR BX,BX
PUSH DS
MOV DS,sbuffer
pr_etq: MOV AH,2
MOV DL,[BX]
XPUSH <BX, CX>
INT 21h
XPOP <CX, BX>
INC BX
LOOP pr_etq
POP DS
LEA DX,crlf_txt
CALL print
no_etiq: MOV AX,brootdir
XOR DX,DX
MOV CL,11+16
CALL print_32 ; entradas en directorio raíz
LEA DX,if1_txt
CALL print
MOV AH,36h
MOV DL,disquetera
INC DL
INT 21h ; obtener espacio en disco
CMP AX,-1
JNE info_espacio
LEA DX,err_info_txt
CALL print
RET
info_espacio: XPUSH <AX, BX, CX, DX>
MOV AX,DX
XOR DX,DX
MOV CL,11+16
CALL print_32 ; número de clusters
LEA DX,if2_txt
CALL print
XPOP <DX, CX, BX, AX>
XPUSH <AX, BX, CX, DX>
MUL CX
MOV CL,11+16
CALL print_32 ; bytes por cluster
LEA DX,if3_txt
CALL print
XPOP <DX, CX, BX, AX>
XPUSH <AX, BX, CX, DX>
MOV BX,DX
MUL CX
MUL BX
MOV CL,11+16
CALL print_32 ; bytes totales
LEA DX,if4_txt
CALL print
XPOP <DX, CX, BX, AX>
XPUSH <AX, BX, CX, DX>
SUB DX,BX
MOV BX,DX
MUL CX
MUL BX
MOV CL,11+16
CALL print_32 ; bytes defectuosos
LEA DX,if5_txt
CALL print
XPOP <DX, CX, BX, AX>
MUL CX
MUL BX
MOV CL,11+16
CALL print_32 ; bytes libres
LEA DX,if6_txt
CALL print
RET
info_fmt ENDP
; ------------ Imprimir errores de trabajo.
pr_error PROC
LEA DX,limpia_txt
CALL print
CALL get_err_crit
TEST errw,0FFFFh
JNZ errorfmt
CLC ; no hubo error
RET
errorfmt: LEA DX,no_2mgui_txt
TEST errw,MALDRV
JZ errorfmt2?
CALL print ; la unidad no es 2MGUI
errorfmt2?: LEA DX,abortado_txt
TEST errw,ABORTADO
JZ errorfmt3?
CALL print ; formateo abortado
errorfmt3?: LEA DX,no_prep_txt
TEST errw,NOPREP
JZ errorfmt4?
CALL print ; unidad no preparada
errorfmt4?: LEA DX,err_prot_txt
TEST errw,PROTESCR
JZ errorfmt5?
CALL print ; protegida contra escritura
errorfmt5?: LEA DX,mal_dens_txt
TEST errw,MALADENS
JZ errorfmt6?
CALL print ; densidad incorrecta
errorfmt6?: LEA DX,mal_sys_txt
TEST errw,MALSYS
JZ errorfmt7?
CALL print ; fallo en áreas del sistema
errorfmt7?: LEA DX,mucha_fat_txt
TEST errw,MUCHAFAT
JZ errorfmt8?
CALL print ; FAT demasiado grande
errorfmt8?: LEA DX,mucha_pis_txt
TEST errw,MUCHAPISTA
JZ errorfmt9?
CALL print ; tamaño de pista no soportado
errorfmt9?: STC ; hubo error
RET
pr_error ENDP
; ------------ Obtener error fatal.
get_err_crit PROC
CMP status,0
JNE hay_crit?
RET
hay_crit?: MOV AX,NOPREP
TEST status,80h
JZ err2?
OR errw,AX ; unidad no preparada
RET
err2?: MOV AX,PROTESCR
CMP status,3
JNE err7f?
OR errw,AX ; protegida contra escritura
RET
err7f?: MOV AX,MUCHAPISTA
CMP status,7Fh
JNE err3
OR errw,AX ; tamaño de pista no soportado
RET
err3: OR errw,MALADENS ; otro caso: mala densidad
RET
get_err_crit ENDP
; ------------ Test de capacidad máxima soportada y velocidad de
; rotación.
test_disk PROC
CALL get_drv
CALL init_flp ; preparar áreas de datos
MOV gaprw,-1 ; rutinas E/S en modo test
MOV [SI].infb.mfrontera,86
LEA DX,test_txt1
CALL print
LEA DX,lin_txt
CALL print ; mensajes de cabecera
MOV AL,[SI].unidad
CALL drvfloppy?
JNC test_drvok
LEA DX,mal_unidad_txt
CALL print
JMP test_ret ; unidad incorrecta
test_drvok: CMP param_dh,ON
JNE test_drvAL
LEA DX,dh_test_txt
CALL print
JMP test_ret ; parámetro /DH en test
test_drvAL: CMP param_nodma,OFF
JE test_posible
CMP pcxt,OFF
JE test_posible
LEA DX,errxtdma_txt
CALL print
JMP test_ret ; PC/XT: sólo vale con DMA
test_posible: LEA DX,test_txt_t
CALL print
MOV AH,0
INT 16h ; pausa inicial
LEA DX,limpia_txt
CALL print
CMP AL,27
JNE hacer_test
test_esc: LEA DX,limpia_txt ; cancelado con ESC
CALL print
LEA DX,test_esc_txt
CALL print
JMP test_ret
hacer_test:
MOV modoDMA,ON ; supuesto con DMA
CMP param_nodma,ON
JNE haz_test
MOV modoDMA,OFF ; pues es sin él
MOV tmodo,0 ; primer test con bits iguales
haz_test: CMP modoDMA,OFF
JE aviso_sincero
CALL vds_dma_ok?
MOV AX,14*1024 ; buffer DMA para 1.44M
CMP [SI].tsector,7
JE tdok
MOV AX,28*1024 ; buffer DMA para 2.88M
tdok: CMP DI,AX
JAE otro_test
LEA DX,test_bdma_txt
CALL print
JMP otro_test
aviso_sincero: LEA DX,test_dma_txt
CALL print
otro_test: CALL test_pista
JC test_fatal ; fallo grave (protegido, etc).
CMP status,1
JNE test_prosigue ; no hay tecla ESC
LEA DX,limpia_txt ; cancelado con ESC
CALL print
LEA DX,test_esc_txt
CALL print
JMP ret_cam_test
test_prosigue: CMP status,2
JNE test_info
CALL pr_error ; mala densidad
JMP ret_cam_test
test_fatal: CALL pr_error ; imprimir error trágico
JMP ret_cam_test
test_info: LEA DX,limpia_txt
CALL print
LEA DX,test_r_txt11c ; información de resultados
CMP modoDMA,ON
JE tif1
LEA DX,test_r_txt11s
tif1: CALL print ; con/sin DMA
LEA DX,test_r_txt12
CALL print
LEA DX,test_r_txt12i
CMP tmodo,0
JE tif2
LEA DX,test_r_txt12d
tif2: CALL print ; bits idénticos/aleatorios
LEA DX,test_r_txt13
CALL print
MOV AX,bytes_ok
SUB AX,SYSBYTES
XOR DX,DX
MOV CL,6+16
CALL print_32 ; bytes soportados
LEA DX,test_r_txt14
CALL print
CMP AX,[SI].infb.tpista2
JAE pr_test_res
CMP modoDMA,OFF
JE pr_test_res ; no decir bobadas en NO-DMA
PUSH AX
MOV AX,243
MUL [SI].infb.tpista2
MOV DH,AH
XCHG DH,DL ; DX = 95% de tpista2
POP AX
CMP AX,DX
JAE info_maldrv ; diferencia modesta
LEA DX,disco_def_txt
CALL print ; ¡lo que casca es el disco!
JMP gap_bien
info_maldrv: LEA DX,test_res_mal
CALL print ; unidad pésima
pr_test_res: LEA DX,test_r_txt15
CALL print
MOV AX,bytes_max
SUB AX,bytes_ok
XOR DX,DX
MOV CL,6+16
CALL print_32 ; imprimir GAP mínimo
LEA DX,test_r_txt14
CALL print
CMP AX,GAPDEF
JBE gap_bien
CMP AX,255
JA gap_bien ; no decir bobadas si es raro
CMP modoDMA,OFF
JE gap_bien ; no decir bobadas en NO-DMA
LEA DX,aviso_gap_txt
CALL print
gap_bien: INC tmodo
CMP tmodo,1
JA no_mas_test
JMP otro_test ; test con bits aleatorios
no_mas_test: LEA DX,test_res_txt3
CALL print
CALL spin_disk ; velocidad rotación
ret_cam_test: CMP instalado,ON
JNE test_ret_cam ; programa no residente
PUSH ES
MOV ES,tsr_seg
MOV ES:[SI].controldrv,ON
MOV ES:[SI].cambiodisco,ON ; simular cambio de disco
POP ES
test_ret_cam: CMP status,3
JE test_ret ; salvo protegido de escritura...
TEST status,80h
JNZ test_ret ; o unidad no preparada...
LEA DX,disco_mal_txt
CALL print ; recordar disco dañado
test_ret: CLC
CALL motor_off_cnt ; cuenta normal detención motor
RET
test_disk ENDP
; --- Determinar la capacidad de la pista.
test_pista PROC
MOV bytes_ok,0 ; supuesto ninguno
MOV AX,tpistamax1
SHL AX,1 ; AX = tpistamax1 * 2
MOV tmax,AX
MOV CL,3
SHR AX,CL ; AX = tpistamax1 / 4
ADD tmax,AX ; máximo posible (tmax+tmin)/2
MOV tmin,0 ; mínimo posible
MOV iter,16 ; como mucho, 16 test
STC
CALL reset_drv
nuevo_test: CALL test_kb
JNC test_proc
JMP test_abortado ; se pulsó ESC
test_proc: MOV status,0
MOV [SI].cilindro,0
MOV [SI].cabezal,0
LEA DX,test_txt2
CALL print ; mensaje de "Probando..."
MOV AX,tmax
ADD AX,tmin
SHR AX,1
MOV [SI].infb.tpista1,AX ; tamaño de prueba
CMP AX,1500
JAE test_cont
JMP test_mal_dens ; aquí pasa algo raro
test_cont: CALL info_bytes
CALL motor_ok
CALL seek_drv
CALL genera_infof
CALL formatea_pista ; 1º intento formateo
CMP status,0
JE test_wr
CALL formatea_pista ; 2º intento formateo
CMP status,0
JNE fallo_test
test_wr: CMP tmodo,1
CMC ; CF==0 si tmodo==0
CALL init_buffer
CALL escribe_pista ; 1º intento escritura
CMP status,0
JE test_rd
CALL escribe_pista ; 2º intento escritura
CMP status,0
JNE fallo_test
test_rd: CMP tmodo,1 ; CF==1 si tmodo==0
CALL init_buffer
CALL lee_pista ; 1º intento lectura
CALL cnt_pista
CMP status,0
JE exito_test
CMP tmodo,1 ; CF==1 si tmodo==0
CALL init_buffer
CALL lee_pista ; 2º intento lectura
CALL cnt_pista
CMP status,0
JNE fallo_test
exito_test: MOV AX,[SI].infb.tpista1 ; funcionó...
MOV bytes_max,AX
MOV AX,tmax
ADD AX,tmin
SHR AX,1
MOV tmin,AX ; ...subir límite mínimo
JMP nuevo_test?
fallo_test: CALL test_err ; falló...
JC aborta_test ; fallo grave
MOV AX,tmax
ADD AX,tmin
SHR AX,1
MOV tmax,AX ; ...bajar límite máximo
nuevo_test?: MOV status,0 ; borrar errores anteriores
MOV AX,tmax
CMP AX,tmin
JBE exit_test
DEC iter ; contador de intentos
JZ exit_test
JMP nuevo_test
test_abortado: MOV status,1 ; indicar test abortado
JMP exit_test
test_mal_dens: MOV status,2 ; probablemente mala densidad
exit_test: CLC
RET
aborta_test: STC
RET
test_pista ENDP
; --- Comprobar qué parte de la pista se ha leído bien.
cnt_pista PROC
XPUSH <ES, AX, BX, CX>
MOV ES,sbuffer
XOR BX,BX
MOV CX,[SI].infb.tpista1
CMP tmodo,0
JE test0
MOV semilla,1 ; bits aleatorios
testx: CALL rnd ; nº "aleatorio" esperado
CMP ES:[BX],AL
JNE test_rt
INC BX
LOOP testx ; comprobar cuántos coinciden
JMP test_rt
test0: CMP BYTE PTR ES:[BX],0 ; bits idénticos
JNE test_rt
INC BX
LOOP test0 ; comprobar cuántos coinciden
test_rt: MOV AX,[SI].infb.tpista1
SHR AX,1
CMP CX,AX
JA test_mal ; ni media pista bien leída
MOV AX,[SI].infb.tpista1
SUB AX,CX
MOV bytes_ok,AX ; los que se han leído bien
MOV status,0
CLC
JMP pista_tr
test_mal: MOV status,2 ; necesaria al menos 1/2 pista
STC
pista_tr: XPOP <CX, BX, AX, ES>
RET
cnt_pista ENDP
; --- Informar de la capacidad en fase de test. A la
; entrada, AX = bytes por pista en prueba.
info_bytes PROC
XOR DX,DX
MOV CL,6+16
CALL print_32 ; capacidad en pruebas
LEA DX,test_txt3
CALL print
MOV DL,disquetera
ADD DL,'A'
MOV AH,2
INT 21h ; imprimir unidad
LEA DX,test_txt4
CALL print
CALL print_dsk_tipo ; imprimir su tipo
LEA DX,test_txt5
CALL print ; códigos de retroceso
RET
info_bytes ENDP
; --- Calcular e imprimir la velocidad de rotación.
spin_disk PROC
PUSH ES
MOV ES,sbuffer
XOR DI,DI
MOV BYTE PTR ES:[DI],1 ; 1 sector
MOV BYTE PTR ES:[DI+1],2 ; de 512 bytes
MOV BYTE PTR ES:[DI+2],0 ; cilindro 0
MOV BYTE PTR ES:[DI+3],0 ; cabezal 0
MOV BYTE PTR ES:[DI+4],0 ; sector 0
MOV BYTE PTR ES:[DI+5],2 ; 512 bytes
POP ES
CLC
CALL reset_drv
CALL motor_ok
CALL seek_drv
CALL formatea_pista ; pista de pruebas
CLC
CALL reset_drv
CALL motor_ok
CALL seek_drv
PUSH DS ; *
MOV AX,350Eh
INT 21h
XPUSH <ES, BX> ; ** preservar INT 0Eh
LEA DX,nueva_int23
MOV AX,2523h
INT 21h ; establecer nueva INT 23h
LEA DX,nueva_irq6 ; (para evitar Ctrl-Break)
MOV AX,250Eh
INT 21h ; establecer nueva INT 0Eh
IN AL,61h
AND AL,0FDh ; inhibir sonido
OR AL,1
OUT 61h,AL
MOV AL,10110100b
OUT 43h,AL ; 8254: cnt2 byte bajo/alto
MOV AL,0FFh
DELAY
OUT 42h,AL
DELAY
OUT 42h,AL ; cuenta 65535
MOV cnt_l,0FFFFh
MOV cnt_h,0
LEA DX,spin0_txt
CALL print ; cabecera
MOV iter,0 ; prueba en curso
repite_spin: CMP iter,10
JBE calc_spin ; como mínimo, 10 test
CALL test_kb
JNC calc_spin
JMP fin_spin
calc_spin: MOV AL,01001010b ; comando de lectura de ID's
CALL fdc_write
JNC spin_b1
JMP err_spin
spin_b1: MOV AL,[SI].unidad
MOV irq6,OFF ; bajar flag de interrupción
CALL fdc_write ; byte 1 de la orden
STC
CALL motor_off_cnt ; evitar que se pare el motor
CMP iter,4
JB calc_rot ; no imprimir 4 primeros test
LEA DX,spin1_txt
CALL print
PUSH SI ; *
MOV SI,dif_l
MOV DI,dif_h
MOV AX,25000
CALL mult32x16 ; resultado en DXDISI
MOV AX,29829
CALL divi48x15 ; 25000 / 29829 =
XOR DX,DX ; = (1/1193180) * 1000000
MOV AX,iter
SUB AX,3 ; nº iteraciones efectivas
CALL divi48x15
MOV DX,DI
MOV AX,SI
POP SI ; *
MOV cntms_h,DX
MOV cntms_l,AX
MOV CL,01100111b
CALL print_32 ; imprimir milisegundos
LEA DX,spin2_txt
CALL print
MOV AX,iter
XOR DX,DX
MOV CL,4
CALL print_32 ; imprimir iteraciones
LEA DX,spin3_txt
CALL print
calc_rot: MOV AX,cnt_l
MOV DX,cnt_h
MOV CX,37 ; timeout en 2 segundos
espera_irq6: CMP irq6,ON
JE llego_irq6
MOV BX,AX
MOV AL,10000100b
OUT 43h,AL ; 8254: enclavar contador 2
DELAY
IN AL,42h
XCHG AH,AL
DELAY
IN AL,42h
XCHG AH,AL ; AX = nueva cuenta
CMP AX,BX
JBE espera_irq6
INC DX
LOOP espera_irq6
JMP err_spin ; timeout
llego_irq6: CMP iter,2
JNE guarda_tm ; desechar 2 primeras pruebas
XPUSH <AX, DX>
MOV CX,65535
SUB CX,AX
MOV AX,65535
MUL DX ; DX:AX clocks del 8254
ADD AX,CX
ADC DX,0
MOV dif0_l,AX
MOV dif0_h,DX ; valor inicial
XPOP <DX, AX>
guarda_tm: MOV cnt_l,AX
MOV cnt_h,DX ; cuenta actual
MOV AX,65535
MUL DX
MOV CX,65535
SUB CX,cnt_l
ADD AX,CX
ADC DX,0 ; DX:AX clocks 8254 actuales
SUB AX,dif0_l
SBB DX,dif0_h
MOV dif_l,AX
MOV dif_h,DX ; tiempo transcurrido
LEA BX,fdc_result
MOV CX,7
sect_rd_res: CALL fdc_read ; leyendo resultados
MOV [BX],AL
INC BX
LOOP sect_rd_res
TEST fdc_result,11000000b ; ¿error?
JNZ err_spin
INC iter
CMP iter,1000
JAE fin_spin ; no más de 1000 test
JMP repite_spin
fin_spin: XPOP <DX, DS> ; **1
MOV AX,250Eh
INT 21h ; restaurar INT 0Eh
POP DS ; *1
CALL informe_spin
RET
err_spin: XPOP <DX, DS> ; **2
MOV AX,250Eh
INT 21h ; restaurar INT 0Eh
POP DS ; *2
LEA DX,spine_txt
CALL print ; indicar que hubo problemas
RET
spin_disk ENDP
; --- Nueva rutina de INT 0Eh.
nueva_irq6 PROC
PUSH AX
MOV AL,20h
OUT 20h,AL ; EOI
POP AX
MOV CS:irq6,ON ; indicar interrupción
nueva_int23: IRET
nueva_irq6 ENDP
; --- Informar sobre la calidad de la disquetera.
informe_spin PROC
LEA DX,spind_txt
CALL print
PUSH SI ; *
MOV DX,cntms_h
MOV AX,cntms_l
MOV DI,3
MOV SI,3392 ; DISI = 200000 (3½ HD)
CMP DX,3
JAE splim_ok
CMP AX,52261
JA splim_ok
MOV DI,2
MOV SI,35594 ; DISI = 166666 (5¼ HD)
splim_ok: SUB AX,SI
SBB DX,DI
JNC spsign_ok
ADD AX,SI
ADC DX,DI
XPUSH <AX, DX> ; signo '-'
MOV DL,'-'
MOV AH,2
INT 21h
XPOP <DX, AX>
XPUSH <SI, DI>
SUB SI,AX
SBB DI,DX
MOV AX,SI
MOV DX,DI ; restado el pequeño del grande
XPOP <DI, SI>
STC
spsign_ok: PUSHF ; ** preservar signo
CMP DX,0
JNE fallo_sp ; muy raro, demasiada diferencia
CMP AX,5000
JA fallo_sp ; muy raro, demasiada diferencia
MOV CL,01100101b
CALL print_32
PUSH AX ; ***
LEA DX,spinf1_txt
CALL print
MOV AX,SI
MOV DX,DI
MOV CL,01100111b
CALL print_32
LEA DX,spinf2_txt
CALL print
POP AX ; ***
POPF ; **1 signo
POP SI ; *1
LEA BX,spinf_calidad
JC busca_calidad ; unidad rápida
XOR AX,AX ; las lentas siempre buenas ;-)
busca_calidad: CMP AX,[BX]
JB dicha_calidad
CMP WORD PTR [BX],0
JE dicha_calidad
ADD BX,4
JMP busca_calidad
dicha_calidad: MOV DX,[BX+2]
CALL print ; imprimir mensaje de calidad
LEA DX,spinf3_txt
CALL print
RET
fallo_sp: POPF ; **2
POP SI ; *2
LEA DX,spine_txt
CALL print ; fallo del test
RET
informe_spin ENDP
; ------------ Rutina para dividir números de 48 por números de 15
; bits sin desbordamientos y con cociente de 48 bits.
; DXDISI/AX --> cociente en DXDISI y resto en AX.
; No se modifican otros registros. No se comprueba si
; el divisor es cero o excede los 15 bits.
divi48x15 PROC
PUSH BX
PUSH CX
XOR BX,BX
MOV CX,49 ; rotar 49 veces
divi48_15_cmp: CMP AX,BX
JA divi48_nosub
SUB BX,AX
STC
divi48_nosub: RCL SI,1
RCL DI,1
RCL DX,1
PUSHF
CMP CX,1
JE divi48_resto ; ¡no rotar el resto al final!
POPF
RCL BX,1
PUSHF
divi48_resto: POPF
LOOP divi48_15_cmp
MOV AX,BX
POP CX
POP BX
RET
divi48x15 ENDP
; ------------ Obtener la unidad física correspondiente a la unidad
; 2MGUI o a la indicada. Si la que se indica no es
; además 2MGUI, CF=1 a la vuelta.
get_drv PROC
MOV AL,disquetera
CMP AL,-1
JNE usar_esa
MOV AL,0
CMP instalado,ON
JNE usar_esa ; la A: si no instalado
PUSH ES
MOV ES,tsr_seg
MOV AL,ES:unidad_base ; por defecto la primera
POP ES
MOV disquetera,AL
usar_esa: CALL drv2mgui?
RET
get_drv ENDP
; ------------ Comprobar si la unidad AL es 2MGUI y devolver en
; ese caso su número físico. AH corrompido.
drv2mgui? PROC
MOV AH,0
CMP instalado,ON
JNE drvn2mg ; si no instalado, no 2MGUI
PUSH ES
MOV ES,tsr_seg
MOV AH,ES:unidad_base
POP ES
SUB AL,AH
JZ drv2mg ; primera unidad 2MGUI
CMP num_discos,1
JE drvn2mg
CMP AL,1
JE drv2mg ; segunda unidad 2MGUI
drvn2mg: ADD AL,AH
STC
RET
drv2mg: MOV AH,info_E.unidad ; primera unidad
AND AL,AL
JZ drv2mg_ok
MOV AH,info_F.unidad ; segunda unidad
drv2mg_ok: MOV AL,AH
CLC
RET
drv2mgui? ENDP
; ------------ Comprobar si la unidad AL es 2MGUI, A: ó B:
drvfloppy? PROC
CMP AL,1
JA es2mgui? ; no es A: ni B:
MOV DL,AL
MOV AH,8
MOV BL,0
CALL tipo_disco ; tipo de la unidad
CMP BL,2
JE drvflp ; de alta densidad
CMP BL,4
JAE drvflp ; de alta densidad
es2mgui?: CALL drv2mgui?
RET
drvflp: CLC
RET
drvfloppy? ENDP
; ------------ Inicializar datos para las rutinas de bajo nivel.
; A la entrada, AL = unidad física.
init_flp PROC
PUSH AX
LEA SI,info_E ; apuntar a datos de la unidad
MOV BX,GAPDEF
MOV CL,modoDMA
CMP instalado,ON
JNE flpn_ok ; usar la primera si no reside
PUSH ES
MOV ES,tsr_seg
MOV BX,ES:gaprw
MOV CL,ES:modoDMA
CMP AL,ES:info_E.unidad ; utilizar la correcta si el
POP ES ; programa está residente
JE flpn_ok
LEA SI,info_F
flpn_ok: MOV [SI].unidad,AL ; en adelante, la unidad física
MOV gaprw,BX
MOV modoDMA,CL ; GAP/modo DMA correcto
CALL get_tpista
MOV [SI].infb.tpista1,AX ; bytes por pista 1ª parte
MOV [SI].infb.tpista2,BX ; bytes por pista 2ª parte
MOV tpistamax1,CX ; bytes máximos teóricos 1ª parte
MOV tpistamax2,DX ; bytes máximos teóricos 2ª parte
MOV BL,7 ; log2 (16384) - 7 = 7
CMP AX,16384
JBE tsecf_ok
INC BL ; log2 (32768) - 7 = 8
tsecf_ok: MOV [SI].tsector,BL
MOV AX,DI
MOV [SI].vunidad1,AL
MOV [SI].infb.vunidad2,AH
MOV AX,bsectini
MOV [SI].bytes_sector,AX
POP AX
RET
init_flp ENDP
; ------------ Devolver tamaño de la pista (para la unidad AL)
; en AX (pistas 1ª parte) y BX (2ª parte) así como los
; límites máximos en CX (1ª parte) y DX (2ª parte) y
; las velocidades de transferencia en DI.
get_tpista PROC
MOV DL,AL
MOV AH,8
CALL tipo_disco ; tipo de la unidad
LEA AX,pista_525
CMP BL,2
JE infpis_ok ; 1.2M
LEA AX,pista_35
CMP BL,4 ; 1.44M
JE infpis_ok
CMP param_ed,ON
JNE infpis_ok
LEA AX,pista_ed ; 2.88M
infpis_ok: MOV BX,10 ; offset información DD
CMP param_dd,ON
JE infdis_ok
MOV BX,20 ; offset información DH
CMP param_dh,ON
JE infdis_ok
XOR BX,BX ; offset información HD
infdis_ok: ADD BX,AX ; direccionar tabla datos
MOV AX,tpista
CMP param_b,ON
JE tp1_ok ; indicado con /B
MOV AX,[BX]
tp1_ok: MOV CX,[BX+2]
MOV DX,[BX+6]
MOV DI,[BX+8]
MOV BX,[BX+4]
CMP param_b,ON
JNE tp2_ok
CMP param_dh,ON
JNE tp3_ok
XPUSH <SI, DI, CX, DX> ; * caso 5¼ /DH
MUL WORD PTR maxpistas
MOV DI,DX
MOV SI,AX
MOV AX,t_525_hd ; tamaño * maxpistas * t_525_hd
CALL mult32x16
MOV AX,20
CALL divi48x15 ; div 20 (problema de rango)
XPUSH <DX, DI, SI>
MOV AX,WORD PTR maxpistas
SUB AL,frontera
SBB AH,0
MOV BX,t_525_dd
MUL BX
MOV CX,DX
MOV BX,AX ; CX:BX = t_525_dd*(maxp - FRO)
XOR DI,DI
MOV SI,t_525_hd
MOV AL,frontera
MOV AH,0
CALL mult32x16
ADD SI,BX
ADC DI,CX
ADC DX,0 ; denominador
MOV AX,20
SUB SI,24 ; redondeo
SBB DI,0
SBB DX,0
CALL divi48x15 ; div 20 (problema de rango)
MOV AX,SI ; cabe en 15 bits
XPOP <SI, DI, DX>
CALL divi48x15
INC SI ; redondeo por el resto
MOV AX,SI ; tamaño primera parte disco
PUSH AX ; **
MOV BX,t_525_dd
MUL BX
MOV BX,t_525_hd
DIV BX
MOV BX,AX ; tamaño segunda parte disco
POP AX ; **
XPOP <DX, CX, DI, SI> ; *
JMP tp2_ok
tp3_ok: MOV BX,AX ; /B afecta a todo el disco
tp2_ok: RET
get_tpista ENDP
; ------------ Imprimir nº de 8 bits en AL.
print_8 PROC
XPUSH <AX, CX, DX>
MOV AH,0
XOR DX,DX
MOV CL,2
CALL print_32
XPOP <DX, CX AX>
RET
print_8 ENDP
; --- Imprimir un nº decimal de 32 bits en DXAX formateado por CL.
;
; Entradas:
; Si bit 4 = 1 --> se imprimirán signos separadores de millar
; bits 0-3 = nº total de dígitos (incluyendo separadores de
; millar y parte fraccional)
; bits 5-7 = nº de dígitos de la parte fraccional (cuantos
; dígitos de DXAX, empezando por la derecha,
; se consideran parte fraccional, e irán precedidos
; del correspondiente separador)
;
; Salidas: nº impreso, ningún registro modificado.
;
; * Ejemplo, si DXAX=9384320 y CL=010 1 1011
; se imprimirá ( '_' representa un espacio en blanco ): __93.843,20
print_32 PROC
PUSH DS
PUSH ES
PUSH CS
PUSH CS
POP DS
POP ES
PUSH AX ; preservar todos los registros
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSHF
MOV formato_pr32,CL ; byte del formato de impresión elegido
MOV CX,",."
CMP idioma_sp,ON
JE separ_pr32
XCHG CH,CL
separ_pr32: MOV millares_pr32,CL ; separador de millares
MOV fracc_pr32,CH ; separador parte fraccional
MOV BX,OFFSET tabla_pr32
MOV CX,10
digit_pr32: PUSH CX
PUSH AX
PUSH DX
XOR DI,DI
MOV SI,1 ; DISI = 1
DEC CX ; CX - 1
JCXZ hecho_pr32
factor_pr32: SAL SI,1
RCL DI,1 ; DISI * 2
MOV DX,DI
MOV AX,SI
SAL SI,1
RCL DI,1
SAL SI,1
RCL DI,1 ; DISI * 8
ADD SI,AX
ADC DI,DX ; DISI = DISI*8 + DISI*2 = DISI*10
LOOP factor_pr32 ; DISI = DISI*10*10* ... (CX-1 veces)
hecho_pr32: POP DX ; luego DISI = 10 elevado a (CX-1)
POP AX ; CX se recuperará más tarde
MOV CL,0FFh
rep_sub_pr32: INC CL
SUB AX,SI
SBB DX,DI ; DXAX = DXAX - DISI
JNC rep_sub_pr32 ; restar el factor cuanto se pueda
ADD AX,SI ; subsanar el desbordamiento:
ADC DX,DI ; DXAX = DXAX + DISI
ADD CL,'0' ; pasar binario a ASCII
MOV [BX],CL
POP CX ; CX se recupera ahora
INC BX
LOOP digit_pr32 ; próximo dígito del número
STD ; transferencias (MOVS) hacia atrás
DEC BX ; BX apunta al último dígito
MOV final_pr32,BX ; último dígito
MOV ent_frac_pr32,BX ; frontera parte entera/fraccional
MOV CL,5
MOV AL,formato_pr32
SHR AL,CL ; AL = nº de decimales
AND AL,AL
JZ no_frac_pr32 ; ninguno
MOV CL,AL
XOR CH,CH
MOV SI,final_pr32
MOV DI,SI
INC DI
REP MOVSB ; correr cadena arriba (hacer hueco)
INC final_pr32
MOV AL,fracc_pr32
MOV [DI],AL ; poner separador de parte fraccional
MOV ent_frac_pr32,SI ; indicar nueva frontera
no_frac_pr32: MOV AL,formato_pr32
TEST AL,16 ; interpretar el formato especificado
JZ poner_pr32 ; imprimir como tal
entera_pr32: MOV CX,final_pr32 ; añadir separadores de millar
SUB CX,ent_frac_pr32
ADD CX,3
MOV SI,final_pr32
MOV DI,SI
INC DI
REP MOVSB ; correr cadena arriba (hacer hueco)
MOV AL,millares_pr32
MOV [DI],AL ; poner separador de millares
INC final_pr32
MOV ent_frac_pr32,SI ; usar esta variable como puntero
SUB SI,OFFSET tabla_pr32
CMP SI,3
JAE entera_pr32 ; próximo separador
poner_pr32: MOV BX,final_pr32
MOV BYTE PTR [BX+1],0 ; delimitador de fin de cadena
MOV BX,OFFSET tabla_pr32
MOV principio_pr32,BX ; inicio de cadena
limpiar_pr32: MOV AL,[BX]
CMP AL,'0'
JE blanco_pr32 ; cero a la izda --> poner " "
CMP AL,millares_pr32 ; separador millares a la izda
JE blanco_pr32
CMP AL,fracc_pr32
JNE acabar_pr32
MOV BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
DEC principio_pr32
acabar_pr32: MOV AL,formato_pr32 ; imprimir
AND AL,00001111b
XOR AH,AH
MOV DX,final_pr32
SUB DX,AX
INC DX ; DX = offset 'principio'
AND AX,AX
JNZ format_pr32 ; longitud especificada por el usuario
MOV DX,principio_pr32 ; longitud obtenida del número
format_pr32: CALL print
POPF ; restaurar todos los registros
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
RET ; salida del procedimiento
blanco_pr32: MOV BYTE PTR [BX],' ' ; sustituir 0 ó separador de millares
INC BX ; a la izda. por espacio en blanco
INC principio_pr32
CMP BX,final_pr32
JB limpiar_pr32
MOV DX,BX ; es el número 0.000.000.00X
JMP SHORT acabar_pr32 ; imprimir
formato_pr32 DB 0
DB 5 DUP (' ') ; espacios en blanco para cubrir la
; mayor plantilla que pueda ser espe-
; cificada en el formato
tabla_pr32 DT 0 ; reservar 14 bytes (nº más ., más ASCIIZ)
DW 0,0 ; aquí se solapa un buffer de 32 bytes
millares_pr32 DB '.' ; separador de millares
fracc_pr32 DB ',' ; " parte fraccional
final_pr32 DW 0 ; offset al último byte a imprimir
principio_pr32 DW 0 ; " " primer " " "
ent_frac_pr32 DW 0 ; offset a la frontera entero-fracc.
DT 0 ; $ - tabla_pr32 = 32 bytes usados por
; INT 21h al principio de print_32
print_32 ENDP
; ------------ Crear tabla con información para formatear.
genera_infof PROC
XPUSHA
PUSH ES
MOV ES,sbuffer
MOV AL,[SI].infb.mfrontera
CMP [SI].cilindro,AL ; 1ª/2ª mitad del disco
MOV AX,tpistamax1
JB pl_ok
MOV AX,tpistamax2
pl_ok: SUB AX,146 ; respetar inicio pista
XOR DX,DX
MOV CX,256+62+PRE_GAP3
DIV CX ; AX sectores de 256 bytes caben
MOV CX,AX
MOV BX,360 ; grados de la circunferencia
MOV AX,sliding_x
MUL CX
DIV BX ; AL = sliding X en sectores
PUSH AX ; *
MOV AX,sliding_y
MUL CX
DIV BX ; AL = sliding Y en sectores
POP BX ; *
MOV AH,AL ; sliding Y
MOV AL,BL ; sliding X
PUSH AX ; *
ADD AL,AH
MOV AH,[SI].cilindro
INC AH ; desplazar incluso cilindro 0
MUL AH ; (cilindro+1) * (X+Y)
MOV DX,AX
POP AX ; *
MUL [SI].cabezal ; cabezal * X
ADD AX,DX
XOR DX,DX ; DX:AX = cil * (X+Y) + cab * X
DIV CX ; DL = DX:AX MOD sectores = dis
SUB DL,CL
NEG DL ; DL = sectores - dis
INC DL ; primer_sector
CMP DL,CL
JB gen_ps_ok
MOV DL,0
gen_ps_ok: MOV BL,CL ; nº sectores
MOV AL,[SI].cabezal
MOV AH,1
XOR DI,DI
MOV ES:[DI],CL ; sectores
MOV ES:[DI+1],AH ; de tamaño 1 (256 bytes)
MOV DH,[SI].cilindro
ADD DI,2
gen_info: MOV ES:[DI],DH ; cilindro
MOV ES:[DI+1],AL ; cabezal
MOV ES:[DI+2],DL ; sector
MOV ES:[DI+3],AH ; tamaño 1 (256 bytes)
AND DL,DL
JNZ gen_tam_ok
MOV AH,[SI].tsector
MOV ES:[DI+3],AH ; el sector 0 es especial
MOV AH,1
gen_tam_ok: INC DL
CMP DL,BL
JB gen_sec_ok
MOV DL,0 ; comenzar desde sector 0
gen_sec_ok: ADD DI,4
LOOP gen_info
POP ES
XPOPA
RET
genera_infof ENDP
; ------------ Formatear una pista.
formatea_pista PROC
XPUSHA ; *
PUSH ES ; **
MOV ES,sbuffer
MOV CL,ES:[0]
MOV CH,0 ; CX sectores
SHL CX,1
SHL CX,1
DEC CX ; nº de bytes - 1
MOV AX,ES
MOV DI,2
CALL calc_dir_DMA ; AX:DI -> base BX y página AH
MOV AL,F_WRITE ; modo DMA para escribir
CALL _prepara_DMA ; programar realmente el DMA
MOV AL,F_FORMAT
CALL fdc_write
JC fallo_fmt
MOV AL,[SI].cabezal
SHL AL,1
SHL AL,1
OR AL,[SI].unidad
CALL fdc_write ; byte 1 de la orden
JC fallo_fmt
MOV AL,ES:[1]
CALL fdc_write ; tamaño general
JC fallo_fmt
MOV AL,ES:[0]
CALL fdc_write ; nº sectores
MOV AL,PRE_GAP3
CALL fdc_write ; GAP3
MOV AL,4Eh
CALL reset_irq
CALL fdc_write ; byte de relleno 4Eh (GAP)
CALL espera_int
fallo_fmt: PUSHF
LEA BX,fdc_result
MOV CX,7
format_res: CALL fdc_read ; leyendo resultados
MOV [BX],AL
INC BX
LOOP format_res
POPF
JC fallo_format
TEST fdc_result,11000000b
JZ format_ret
fallo_format: STC ; fallo
CALL set_err
format_ret: POP ES ; **
XPOPA ; *
RET
formatea_pista ENDP
; ------------ Devolver nº aleatorio de 16 bits en AX.
rnd PROC
CMP semilla,0
JNE dev_rnd
PUSH DS
MOV AX,40h
MOV DS,AX
MOV AX,DS:[6Ch] ; contador hora BIOS
POP DS ; como semilla
MOV semilla,AX
dev_rnd: XPUSH <BX, CX>
MOV AX,semilla
MOV BX,AX
MOV CL,7
SHR AX,CL
XOR AX,BX
AND AX,1
ROR AX,1
SHR BX,1
OR AX,BX
MOV semilla,AX
XPOP <CX, BX>
RET
semilla DW 0
rnd ENDP
; ***********************************************
; * *
; * D A T O S N O R E S I D E N T E S *
; * *
; ***********************************************
; ------------ Parámetros soportados
param_ayuda DB OFF ; a ON si se indicó /? /H ó ?
param_dd DB OFF ; a ON si se indicó /DD
param_dh DB OFF ; a ON si se indicó /DH
param_ed DB OFF ; a ON si se indicó /ED
param_dron DB OFF ; a ON si se indicó /DRON
param_droff DB OFF ; a ON si se indicó /DROFF
param_dwon DB OFF ; a ON si se indicó /DWON
param_dwoff DB OFF ; a ON si se indicó /DWOFF
param_n DB OFF ; a ON si se indicó /N
param_k DB OFF ; a ON si se indicó /K
param_test DB OFF ; a ON si se indicó /TEST
param_nodma DB OFF ; a ON si se indicó /NODMA
param_ems DB OFF ; a ON si se indicó /EMS
param_q DB OFF ; a ON si se indicó /Q
param_t DB OFF ; a ON si se indicó /T=
param_r DB OFF ; a ON si se indicó /R=
param_c DB OFF ; a ON si se indicó /C=
param_s DB OFF ; a ON si se indicó /S=
param_f DB OFF ; a ON si se indicó /F=
param_b DB OFF ; a ON si se indicó /B=
param_x DB OFF ; a ON si se indicó /X=
param_y DB OFF ; a ON si se indicó /Y=
param_m DB OFF ; a ON si se indicó /M=
param_g DB OFF ; a ON si se indicó /G=
ptr_label DW 0 ; != NULL si se indicó /L
ptr_ilabel DW 0 ; != NULL si se indicó /V
disquetera DB -1 ; unidad seleccionada si se indica
parametros LABEL BYTE
DB "*:",3
DB 'A'
DB 26
DW disquetera
DB "?",0
DW param_ayuda
DB ON
DB "/?",0
DW param_ayuda
DB ON
DB "/H",0
DW param_ayuda
DB ON
DB "/DD",0
DW param_dd
DB ON
DB "/DH",0
DW param_dh
DB ON
DB "/ED",0
DW param_ed
DB ON
DB "/DRON",0
DW param_dron
DB ON
DB "/DROFf",0
DW param_droff
DB ON
DB "/DWON",0
DW param_dwon
DB ON
DB "/DWOFf",0
DW param_dwoff
DB ON
DB "/TEst",0
DW param_test
DB ON
DB "/NOdma",0
DW param_nodma
DB ON
DB "/EMs",0
DW param_ems
DB ON
DB "/B",1
DW 0, MPISTA
DW tpista
DW param_b
DB ON
DB "/X",1
DW 0, 359
DW sliding_x
DW param_x
DB ON
DB "/Y",1
DW 0, 359
DW sliding_y
DW param_y
DB ON
DB "/M",1
DW 0, 86
DW frontera
DW param_m
DB ON
DB "/G",1
DW 0, 999
DW gaprw
DW param_g
DB ON
DB "/N",0
DW param_n
DB ON
DB "/K",0
DW param_k
DB ON
DB "/I",0
DW param_i
DB ON
DB "/Q",0
DW param_q
DB ON
DB "/T",1
DW 80, 86
DW maxpistas
DW param_t
DB ON
DB "/C",2
DW 8,128,256,512,1024,2048,4096,8192,16384
DW tcluster
DW param_c
DB ON
DB "/S",2
DW 3,128,256,512
DW bsectini
DW param_s
DB ON
DB "/R",1
DW 1, 240
DW rootdir
DW param_r
DB ON
DB "/F",1
DW 1, 2
DW nfats
DW param_f
DB ON
DB "/L",4
DW ptr_label
DB "/V",4
DW ptr_ilabel
DB 0 ; fin de la tabla
; ------------ Constantes y variables
ON EQU 1 ; constantes booleanas
OFF EQU 0
ERRSINTAX EQU 1 ; tipos de errores
MALDOS EQU 2
MALDRV EQU 4
MALBIOS EQU 8
ERRRANGO EQU 16
POCAMEM EQU 32
YAINST EQU 64
NOINST EQU 128
MX64FULL EQU 256
DMACRUCE EQU 512
DMAPOCO EQU 1024
PARAMCONFIG EQU 2048
ABORTADO EQU 8
NOPREP EQU 16
MALADENS EQU 32
PROTESCR EQU 64
MALSYS EQU 128
MUCHAFAT EQU 256
MUCHAPISTA EQU 512
error DW 0 ; de instalación
errw DW 0 ; al formatear/test, etc.
disco DB ?
emmtipo DW ? ; tipo de EMM en INT 4Bh
psp DW ? ; dirección del PSP
emm_id DB "EMMXXXX0" ; identificación controlador EMS
emm_nombre DB "2MGUI",0,0,0 ; nombre para el handle EMS
null DB "NUL",0 ; dispositivo NUL
instalado DB ? ; a ON si 2MGUI instalado
offsets_ints DW 3 ; número de vectores interceptados
DB 8h ; tabla de offsets de los vectores
DW ges_int08 ; de interrupción interceptados
DB 13h
DW ges_int13
DB 2Fh
DW ges_int2F
; --- El disco está dividido en dos partes: desde el
; cilindro 0 hasta FRONTERA-1 y desde FRONTERA
; hasta maxpistas-1. Cada parte tiene sus propias
; características (en la práctica, sólo en 360DH).
pista_525 LABEL WORD
DW t_525_hd ; 1.2M 1ª parte HD
DW m_525_hd ; límite físico 1ª parte HD
DW t_525_hd ; 1.2M 2ª parte HD
DW m_525_hd ; límite físico 2ª parte HD
DW 0000h ; velocidad
DW t_525_dd ; 1.2M 1ª parte DD
DW m_525_dd ; límite físico 1ª parte DD
DW t_525_dd ; 1.2M 2ª parte DD
DW m_525_dd ; límite físico 2ª parte DD
DW 0101h ; velocidad
DW t_525_hd ; 1.2M 1ª parte DH
DW m_525_hd ; límite físico 1ª parte DH
DW t_525_dd ; 1.2M 2ª parte DH
DW m_525_dd ; límite físico 2ª parte DH
DW 0100h ; velocidad
pista_35 LABEL WORD
DW t_35_hd ; 1.44M 1ª parte HD
DW m_35_hd ; límite físico 1ª parte HD
DW t_35_hd ; 1.44M 2ª parte HD
DW m_35_hd ; límite físico 2ª parte HD
DW 0000h ; velocidad
DW t_35_dd ; 1.44M 1ª parte DD
DW m_35_dd ; límite físico 1ª parte DD
DW t_35_dd ; 1.44M 2ª parte DD
DW m_35_dd ; límite físico 2ª parte DD
DW 0101h ; velocidad
DW t_35_dd ; 1.44M 1ª parte DD
DW m_35_dd ; límite físico 1ª parte DD
DW t_35_dd ; 1.44M 2ª parte DD
DW m_35_dd ; límite físico 2ª parte DD
DW 0101h ; velocidad
pista_ed LABEL WORD
DW t_35_ed ; 2.88M 1ª parte ED
DW m_35_ed ; límite físico 1ª parte ED
DW t_35_ed ; 2.88M 2ª parte ED
DW m_35_ed ; límite físico 2ª parte ED
DW 0303h ; velocidad
DW t_35_ed ; 2.88M 1ª parte ED
DW m_35_ed ; límite físico 1ª parte ED
DW t_35_ed ; 2.88M 2ª parte ED
DW m_35_ed ; límite físico 2ª parte ED
DW 0303h ; velocidad
DW t_35_ed ; 2.88M 1ª parte ED
DW m_35_ed ; límite físico 1ª parte ED
DW t_35_ed ; 2.88M 2ª parte ED
DW m_35_ed ; límite físico 2ª parte ED
DW 0303h ; velocidad
maxpistas DB PISTAS
DB 0 ; ¡la captura de parámetros usa DW, no DB!
rootdir DW MINROOT ; mínimo por defecto
bsectini DW SECTDEF ; tamaño de sector por defecto
tcluster DW CLUSDEF ; tamaño de clúster por defecto
nfats DB 1
DB 0 ; ¡la captura de parámetros usa DW, no DB!
tipofat DB ?
fbuffer DW 0 ; segmento para la FAT
srootdir DW ? ; sectores ocupados por el raíz
tpista DW ? ; valor de /B= si se indica
tpistamax1 DW ? ; bytes por pista físicamente máximos
tpistamax2 DW ? ; ...y en la segunda parte del disco
sliding_x DW SLID_X ; grados angulares de sliding /X
sliding_y DW SLID_Y ; grados angulares de sliding /Y
frontera DB FRONT ; frontera división del disco 2 mitades
DB 0 ; ¡la captura de parámetros usa DW, no DB!
tmodo DB ? ; 0->pista a 0, 1->con datos aleatorios
bytes_ok DW ? ; bytes bien leídos durante el test
bytes_max DW ? ; máximos bytes soportados último éxito
tmax DW ? ; máximo/mínima capacidad por pista
tmin DW ? ; durante el test
iter DW ? ; contador de iteraciones
irq6 DB ? ; a ON cuando llega dicha IRQ en el test
cnt_h DW ? ; contadores de tiempo para spin
cnt_l DW ?
dif_l DW 0 ; variación de los contadores
dif_h DW 0
cntms_h DW 0 ; milisegundos * 1000
cntms_l DW 0
dif0_l DW 0 ; valor inicial
dif0_h DW 0
sector_boot LABEL BYTE ; sector de arranque de 128 bytes
JMP SHORT arranque
NOP
DB "2MGUI-10" ; ID sistema: versión 1.0
boot_tsect DW ? ; bytes/sector
bscluster DB ? ; sectores por cluster
DW 1 ; sectores reservados al principio
bnfats DB ? ; nº copias de la FAT
brootdir DW ? ; entradas al directorio raíz
bsectores DW ? ; nº total de sectores del disco
media_id DB 0FAh ; byte descriptor de medio
bsectfat DW ? ; sectores ocupados por la FAT
DW 1 ; sectores por pista
DW 1 ; nº de cabezales
DD 0 ; sectores especiales reservados
DD 0 ; nº sectores (unidad 32 bit)
DB 0 ; unidad física
DB 0 ; reservado
DB 29h ; disco con número de serie
bserie DD 12345678h ; número de serie
DB "NO NAME " ; título del disco
ftipo DB "FAT12 " ; tipo de FAT
arranque: CLI
HLT
DB "(C) 1995 "
DB "Ciriaco García de Celis - "
DB "Valladolid/Spain"
DB 0
PINFOBOOT EQU 74h ; offset físico del área con información
bootp InfoBoot <> ; información del BOOT
DB 126 DUP (0)
DW 0AA55h ; para el DOS, por si es de 256 bytes
DB 254 DUP (0)
DW 0AA55h ; para el DOS, por si es de 512 bytes
; --- Información IOCTL por defecto.
info_drv120 DB 4, 1 ; sectores iguales / tipo 1.2M
DW 2, 13118 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 128 ; BPB: bytes por sector
DB 8 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 1 ; BPB: número de FATs
DW 132 ; BPB: entradas en el raíz
DW 13118 ; BPB: nº total de sectores
DB 0FAh ; BPB: descriptor de medio
DW 20 ; BPB: sectores por FAT
DW 1, 1 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
info_drv144 DB 4, 7 ; sectores iguales / tipo 1.44M
DW 2, 15776 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 128 ; BPB: bytes por sector
DB 8 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 1 ; BPB: número de FATs
DW 156 ; BPB: entradas en el raíz
DW 15776 ; BPB: nº total de sectores
DB 0FAh ; BPB: descriptor de medio
DW 24 ; BPB: sectores por FAT
DW 1, 1 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
info_drv288 DB 4, 9 ; sectores iguales / tipo 2.88M
DW 2, 31552 ; detecta cambio / nº pistas
DB 0 ; tipo de soporte
DW 128 ; BPB: bytes por sector
DB 16 ; BPB: sectores por cluster
DW 1 ; BPB: sectores reservados
DB 1 ; BPB: número de FATs
DW 156 ; BPB: entradas en el raíz
DW 31552 ; BPB: nº total de sectores
DB 0FAh ; BPB: descriptor de medio
DW 24 ; BPB: sectores por FAT
DW 1, 1 ; BPB: sectores pista / cabezas
DB 14 DUP (0) ; BPB: restantes campos
; ------------ Mensajes de instalación.
programa_txt DB 13,10,"2MGUI 1.0 ",13,10,0
instalado_txt DB " Instalado en unidad(es) "
tabla_letras1 DB "A: ",13,10,255
DB " Installed on drive(s) "
tabla_letras2 DB "A: ",13,10,0
errxtdma_txt DB " - Nota: Sistema PC/XT, soportado sólo modo DMA.",13,10,255
DB " - Note: PC/XT system, supported only DMA mode.",13,10,0
erremsins_txt DB " - Nota: No ha sido posible utilizar memoria EMS.",13,10,255
DB " - Note: It isn't possible to use EMS memory.",13,10,0
erremsdma_txt DB " - Nota: Sólo se puede utilizar EMS en modo /NODMA.",13,10,255
DB " - Note: To use EMS is only possible in /NODMA mode.",13,10,0
mal_dos_txt DB " - Error: Necesario DOS 3.30 o posterior.",13,10,255
DB " - Error: Needs DOS 3.30 or above.",13,10,0
mal_bios_txt DB " - Error: No puedo detectar el tipo de las unidades. Instale 2M-?BIOS antes.",13,10,255
DB " - Error: Impossible to detect drive types. Please install 2M-?BIOS before.",13,10,0
mal_drv_txt DB " - Error: Necesaria(s) unidad(es) de alta densidad.",13,10,255
DB " - Error: Needs high-density floppy drive(s).",13,10,0
ya_ins_txt DB " - Error: Programa ya instalado en memoria.",13,10,255
DB " - Error: Program already loaded on memory.",13,10,0
dma_front_txt DB " - Consejo: Modifique la ubicación en memoria de este programa (variando el",13,10
DB " orden de instalación de dispositivos) o, alternativamente, pruebe",13,10
DB " a instalarlo en modo NO-DMA. El motivo es economizar memoria, ya",13,10
DB " que se cruza una frontera de DMA. No obstante, el programa puede",13,10
DB " funcionar perfectamente así, ocupando más memoria.",13,10,255
DB " - Advice: Modify the memory location of this utility (variying the devices",13,10
DB " installation order) or install the program in Non-DMA mode, to save",13,10
DB " memory. The problem is that 2MGUI crosses a DMA frontier. But this",13,10
DB " program can work correctly in this way (taking more memory).",13,10,0
dma_poco_txt DB " - Nota: El buffer DMA de su controlador de memoria es demasiado pequeño,",13,10
DB " auméntelo a 13 (1.44M) ó 25 (2.88M) Kbytes.",255
DB " - Note: The DMA buffer of your memory manager is too small; set it",13,10
DB " to 13 (1.44M) or 25 (2.88M) Kbytes.",0
emm_qemm_txt DB " En su controlador de",13,10
DB " memoria (QEMM) basta que le añada la opción DMA=13 ó DMA=25.",13,10,255
DB " With your memory manager (QEMM) you must add",13,10
DB " to it a DMA=13 or DMA=25 switch.",13,10,0
nocabe_txt DB " Instalación imposible:",13,10
DB " Ya hay 64 programas residentes con la misma técnica.",13,10,255
DB " Unable to install:",13,10
DB " There are already 64 TSR's with the same technique.",13,10,0
err_sintax_txt DB " - Error de sintaxis o parámetro fuera de rango.",13,10,255
DB " - Syntax error or parameter out of range.",13,10,0
pet_ayuda_txt DB " Ejecute 2MGUI /? si desea obtener ayuda.",13,10,255
DB " Execute 2MGUI /? to obtain more help.",13,10,0
no_ins_txt DB " - Error: Instale este programa primero en CONFIG.SYS",13,10,255
DB " - Error: First, install this program in CONFIG.SYS",13,10,0
err_mem_txt DB " - Error: memoria insuficiente.",13,10,255
DB " - Error: insufficient memory.",13,10,0
; ------------ Mensajes varios.
limpia_txt DB 13," ",13,0
lin_txt DB "───────────────────────────────────────────────────────────────────────────────",13,10,0
err_prot_txt DB 13," - Disco protegido contra escritura.",13,10,255
DB 13," - Write protected disk error.",13,10,0
no_prep_txt DB 13," - Unidad no preparada.",13,10,255
DB 13," - Drive not ready.",13,10,0
mal_dens_txt DB 13," - Anomalía general. ¿Densidad incorrecta?.",13,10,255
DB 13," - General failure. Incorrect density?.",13,10,0
mal_unidad_txt DB " - La unidad no existe o no es de alta densidad.",13,10,255
DB " - Diskette drive doesn't exist or it isn't high-density.",13,10,0
dh_test_txt DB " - El parámetro /DH no puede indicarse junto a /TEST.",13,10,255
DB " - The /DH switch can not be used with /TEST.",13,10,0
pconfig_txt DB " - El parámetro /NODMA sólo puede indicarse en CONFIG.SYS o con /TEST; y ",13,10
DB " el parámetro /EMS sólo puede indicarse en CONFIG.SYS y junto a /NODMA.",13,10,255
DB " - The /NODMA switch can only be used in CONFIG.SYS or with /TEST; and",13,10
DB " the /EMS switch can only be used in CONFIG.SYS and with /NODMA.",13,10,0
crlf_txt DB 13,10,0
; ------------ Informe de unidades.
hay_2mgui_txt DB 13,10
DB "2MGUI 1.0 ya instalado en memoria.",13,10,255
DB 13,10
DB "2MGUI 1.0 already installed in memory.",13,10,0
hay_en_txt DB " - Nueva unidad ",255
DB " - New drive ",0
nueva_u DB "E: ",0
hay2_txt DB " (unidad física ",255
DB " (physical drive ",0
vieja_u DB "A"
DB ":)",13,10,0
gap_txt DB " - GAP anti-FIFO de",255
DB " - Anti-FIFO GAP of",0
dma1_txt DB " bytes y modo ",255
DB " bytes and ",0
dmano_txt DB "NO-",255,"non-",0
dma2_txt DB "DMA.",13,10,255
DB "DMA mode.",13,10,0
buffer_ems_txt DB " - Buffer interno ubicado en memoria EMS.",13,10,255
DB " - Internal buffer placed in EMS memory.",13,10,0
cache_off_txt DB " - Escritura retardada desactivada.",13,10,255
DB " - Delayed-write disabled.",13,10,0
sopdr_on_txt DB " - Soporte para DISKCOPY DR-DOS y Novell DOS activo.",13,10,255
DB " - DR-DOS and Novell DOS DISKCOPY support enabled.",13,10,0
; ------------ Mensajes de formateo.
no_2mgui_txt DB 13,10,"2MGUI 1.0",13,10
DB " - Error: La unidad indicada no es un dispositivo 2MGUI.",13,10,255
DB 13,10,"2MGUI 1.0",13,10
DB " - Error: Drive indicated does not is a 2MGUI device.",13,10,0
mucha_fat_txt DB 13,10,"2MGUI 1.0",13,10
DB " - Error: Memoria insuficiente para una FAT tan grande.",13,10,255
DB 13,10,"2MGUI 1.0",13,10
DB " - Error: Insufficient memory for so big a FAT.",13,10,0
fmtm1_txt DB 13,10,"2MGUI 1.0 Formateando",255
DB 13,10,"2MGUI 1.0 Formatting",0
fmtm2_txt DB " bytes por pista en ",255
DB " bytes per track in ",0
fmtm3_txt DB ": ",0
fmtm4_txt DB " (ESC Salir)",13,10,255
DB " (ESC Aborts)",13,10,0
fmtm5_txt DB " Inicializando disquete de ",255," Initializing ",0
fmtm6_txt DB " con",255," diskette with",0
fmtm7_txt DB "K",13,10,0
pausaf_txt DB " Pulsa INTRO para formatear u otra tecla para terminar...",255
DB " Press ENTER key to begin format or another key to exit...",0
abortado_txt DB 13," - Formateo interrumpido por el usuario.",13,10,255
DB 13," - Format aborted by user. ",13,10,0
mucha_pis_txt DB 13," - La unidad no soporta tanta capacidad en la pista.",13,10,255
DB 13," - This drive doesn't support so big a track.",13,10,0
mal_sys_txt DB 13," - Fatal: fallo en áreas del sistema.",13,10,255
DB 13," - Fatal: failure on system areas.",13,10,0
cil_txt DB 13," Cilindro ",255,13," Cylinder ",0
cab_txt DB " Cara",255," Side",0
p_txt DB " ",0
f_txt DB 8,8,8,8,8,"[F--]",0
w_txt DB 8,8,8,8,8,"[-X-]",0
v_txt DB 8,8,8,8,8,"[--V]",0
error_txt DB 13,10,"Error",0
t_drvs DW t360, t1200, t720, t1440, t2880, t2880
t360 DB "360K",0
t1200 DB "1.2M",0
t720 DB "720K",0
t1440 DB "1.44M",0
t2880 DB "2.88M",0
capacidad1_txt DB 13," Espacio bruto en disco de",255
DB 13," Crude disk space is",0
capacidad2_txt DB " bytes.",13,10,0
etiq_txt DB " Etiqueta de volúmen ",255
DB " Volume label ",0
err_info_txt DB " - Retire e introduzca el disco antes de usarlo.",13,10,255
DB " - Extract and reinsert the disk before using it.",13,10,0
if1_txt DB " ficheros permitidos en el raíz.",13,10,255
DB " file capacity of root directory.",13,10,0
if2_txt DB " unidades de asignación.",13,10,255
DB " total clusters on disk.",13,10,0
if3_txt DB " bytes por unidad de asignación.",13,10,255
DB " bytes per cluster.",13,10,0
if4_txt DB " bytes totales en el disco.",13,10,255
DB " total bytes on disk.",13,10,0
if5_txt DB " bytes en sectores defectuosos.",13,10,255
DB " bytes in bad tracks.",13,10,0
if6_txt DB " bytes disponibles en el disco.",13,10,255
DB " bytes available on disk.",13,10,0
; ------------ Mensajes para el test.
test_txt1 DB 13,10,10,"2MGUI 1.0: TEST DE CAPACIDAD Y CALIDAD DE LA UNIDAD (ESC Salir)",13,10,255
DB 13,10,10,"2MGUI 1.0: DISKETTE DRIVE MAXIMUM CAPACITY AND QUALITY TEST (ESC Aborts)",13,10,0
test_txt_t DB " - Introduzca un disco que PERDERA TODOS LOS DATOS y pulse una tecla.",255
DB " - Insert a disk which will LOSE ALL DATA and press any key.",0
test_dma_txt DB " NOTA: El test puede producir resultados absurdos si su sistema o la",13,10
DB " configuración del mismo no soporta el acceso en modo NO-DMA.",13,10,255
DB " NOTE: This test may return nonsense results if your hardware or your",13,10
DB " system configuration does not support Non-DMA diskette access mode.",13,10,0
test_bdma_txt DB " NOTA: El buffer de DMA de su PC es demasiado pequeño; cambie la configuración",13,10
DB " del controlador de memoria si se cuelga o si aparece alguna excepción. Con",13,10
DB " QEMM basta añadir DMA=14 (1.44M) ó DMA=28 (2.88M) [algo más de lo normal].",13,10,255
DB " NOTA: The maximum DMA buffer on your PC is too small; if the PC hangs during",13,10
DB " the test or the EMM reports a exception, set a bigger buffer. With QEMM you",13,10
DB " can add a DMA=14 (1.44M) or a DMA=28 (2.88M) [a little more than normal].",13,10,0
test_txt2 DB 13," Probando ",255
DB 13," Testing ",0
test_txt3 DB " bytes en ",255
DB " bytes in ",0
test_txt4 DB ": [Disco de ",255
DB ": [",0
test_txt5 DB "] ",8,8,8,8,8,8,255
DB " diskette] ",8,8,8,8,8,8,0
test_r_txt11c DB 13," - Con ",255
DB 13," - With ",0
test_r_txt11s DB 13," - Sin ",255
DB 13," - Without ",0
test_r_txt12 DB "DMA y bits ",255
DB "DMA and ",0
test_r_txt12i DB "idénticos",255
DB "identic bits",0
test_r_txt12d DB "aleatorios",255
DB "random bits",0
test_r_txt13 DB " máxima capacidad por pista:",9,255
DB " maximum size in each track:",9,0
test_r_txt14 DB " bytes.",13,10,0
test_r_txt15 DB " Mínimo posible GAP anti-FIFO detectado:",9,9,9,255
DB " Possible minimum anti-FIFO GAP detected:",9,9,9,0
aviso_gap_txt DB " AVISO:",13,10
DB " - Su controladora precisa un GAP anti-FIFO mayor del establecido por defecto",13,10
DB " por el programa; indíquelo explícitamente con la opción /G al instalarlo.",13,10,255
DB " IMPORTANT:",13,10
DB " - Your diskette controller needs a bigger anti-FIFO GAP than default settings",13,10
DB " for program; set it with /G switch during program installation.",13,10,0
test_res_txt3 DB " NOTAS SOBRE LOS PARAMETROS /B Y /G:",13,10
DB " - El valor máximo soportado por /B para lograr más capacidad en los disquetes",13,10
DB " será normalmente la capacidad máxima en la pista MENOS el GAP anti-FIFO (20",13,10
DB " bytes por defecto). Es decir, reste 20 bytes de la capacidad de la pista",13,10
DB " para obtener el valor máximo de /B. Ajustando también dicho GAP con /G se",13,10
DB " puede obtener aún más capacidad. Cuidado: /G varía ligeramente con EMM386.",13,10
DB " - Use siempre los datos del test de PEOR resultado de todos los realizados.",13,10
DB " - Recuerde que estos disquetes serán *estropeados* al ser ESCRITOS por otras",13,10
DB " unidades que admitan menos capacidad, aunque podrán LEERSE sin problemas.",13,10
DB " - No utilice los valores límites si quiere que el programa funcione.",13,10,255
DB " NOTES ABOUT /B AND /G SWITCHES:",13,10
DB " - The maximum value supported by /B switch to get more disk capacity, will be",13,10
DB " usually the maximum size per track but SUBSTRACTING anti-FIFO GAP (20 bytes",13,10
DB " by default). This means that you have to substract 20 bytes to the maximum",13,10
DB " track size to obtain /B value. Adjusting also this GAP with /G switch, it's",13,10
DB " also possible to get more capacity. Warning: /G vary slightly with EMM386.",13,10
DB " - You must use always the results of WORST test of all performed.",13,10
DB " - Remember that this diskettes will be *damaged* when WRITTING them on other",13,10
DB " drives with less capacity, although they can be READED without problems.",13,10
DB " - Choosing minimum/maximum limits for values, the program may not work.",13,10,0
disco_def_txt DB " - Nota: ¡Este disco quizá tenga defectuosa la pista 0!.",13,10,255
DB " - Note: your diskette is perhaps damaged on track 0!",13,10,0
test_res_mal DB " - Su unidad de disco es pésima y no admite siquiera la capacidad mínima",13,10
DB " que necesita el programa. Cómprese otra mejor y, mientras tanto, no",13,10
DB " escriba sobre los discos 2MGUI que le pasen otras personas.",13,10,255
DB " - Your diskette drive is very bad and doesn't support the minimum size",13,10
DB " needed by this program. You must buy a better drive and, meanwhile, do",13,10
DB " not write on 2MGUI disks that other people send to you (only read!).",13,10,0 ;;;
spin0_txt DB " TEST DE VELOCIDAD DE ROTACION:",13,10,255
DB " ROTATION SPEED TEST:",13,10,0
spin1_txt DB 13," - Período de rotación: ",255
DB 13," - Rotation period: ",0
spin2_txt DB " ms (",0
spin3_txt DB ") [ESC-Fin]",255,") [ESC-End]",0
spind_txt DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"; con una desviación de ",255
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"; with a shift of ",0
spinf1_txt DB " ms",13,10," sobre al valor esperado de ",255
DB " ms from the",13,10," expected value of ",0
spinf2_txt DB " ms (unidad de ",255
DB " ms (",0
spinf3_txt DB " calidad).",13,10,255
DB " quality drive).",13,10,0
spinf_calidad DW 100
DW c_altisima
DW 250
DW c_alta
DW 500
DW c_mediana
DW 750
DW c_mala
DW 1000
DW c_pesima
DW 0
DW c_pesima
c_altisima DB "muy elevada",255,"very high",0
c_alta DB "alta",255,"high",0
c_mediana DB "mediana",255,"medium",0
c_mala DB "baja",255,"bad",0
c_pesima DB "pésima",255,"very bad",0
spine_txt DB 13," Nota: ha habido algún problema calculando el período de rotación.",13,10,255
DB 13," Note: it have been some problem computing rotation period.",13,10,0
test_esc_txt DB 13," - TEST interrumpido por el usuario.",13,10,255
DB 13," - TEST aborted by user.",13,10,0
disco_mal_txt DB " RECUERDE QUE EL DISCO DE PRUEBA ESTA INSERVIBLE: DEBERA FORMATEARLO.",13,10,255
DB " REMEMBER THAT TEST DISK IS NOW DAMAGED: YOU MUST FORMAT IT BEFORE USE.",13,10,0
; ------------ Ayuda.
ayuda_txt LABEL BYTE
DB 13,10,10
DB " 2M GUINNESS 1.0 - ACCESO DIRECTO A DISCO SIN CONTROLADORA",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10
DB 10
DB " 2MGUI [U:] [/DD] [/DH] [/ED] [/T:n] [/R:n] [/C:n] [/S:n] [/F:n] [/N] [/K]",13,10
DB 10
DB " Este programa obtiene *toda* la capacidad de los discos antes de formatear;",13,10
DB " pudiendo incluso adaptarse a la velocidad de la unidad para obtener aún más.",13,10
DB 10
DB " Instálelo primero en el CONFIG.SYS con una línea como «DEVICE=2MGUI.EXE»;",13,10
DB " a raíz de ello se crearán tantas nuevas letras como unidades de alta densidad",13,10
DB " haya en el sistema. Los discos formateados por este programa sólo podrán ser",13,10
DB " accedidos en esas nuevas unidades, que también soportan discos estándar (y 2M",13,10
DB " si 2M está instalado). Es más, este programa permite utilizar discos 2M bajo",13,10
DB " OS/2 en esas nuevas unidades. Al conmutar entre dichas unidades y las físicas",13,10
DB " se simula un cambio de disco automático (y no se pide nuevo disco).",13,10
DB 10
DB " Para formatear los nuevos discos, ejecute 2MGUI indicando la unidad que les",13,10
DB " soporta. Por defecto se utiliza alta densidad; /DD selecciona doble densidad,",13,10
DB " /DH formatea 1/3 en alta densidad y 2/3 en doble (sólo discos de 360K) y /ED",13,10
DB " selecciona 2.88M; /T indica el nº de pistas (80-86, por defecto 82), /R el",13,10
DB " nº mínimo de ficheros en el raíz (1-240); /C el tamaño de cluster (128-16384)",13,10
DB " y /S el de sector (128-512), ambos han de ser potencia de 2; /F el nº de FATs",13,10
DB " (1-2); /N no verifica y /K evita las pausas.",13,10
DB " (1/5) [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " ┌───────────┬───────────┬────────────┐",13,10
DB " │ Doble │ Alta │ Extraalta │",13,10
DB " ┌───────────────────────────────┼───────────┼───────────┼────────────┼──────┐",13,10
DB " │ Récord absoluto previo a 2M │ 820.0 Kb │ 1394.0 Kb │ -- │ │",13,10
DB " │ Capacidad máxima 2M (2MF /M) │ 902.0 Kb │ 1558.0 Kb │ -- │ 5.25 │",13,10
DB " │ Capacidad mínima de 2MGUI │ 976.6 Kb │ 1639.8 Kb │ 1203.1 Kb# │ (5¼) │",13,10
DB " │ Capacidad límite física (82p) │ 1001.0 Kb │ 1668.2 Kb │ 1228.8 Kb# │ │",13,10
DB " ├───────────────────────────────┼───────────┼───────────┼────────────┼──────┤",13,10
DB " │ Récord absoluto previo a 2M │ 984.0 Kb │ 1722.0 Kb │ 2880.0 Kb │ │",13,10
DB " │ Capacidad máxima 2M (2MF /M) │ 1066.0 Kb │ 1886.0 Kb │ 3772.0 Kb* │ 3.5 │",13,10
DB " │ Capacidad mínima de 2MGUI │ 1176.0 Kb │ 1972.0 Kb │ 3944.0 Kb* │ (3½) │",13,10
DB " │ Capacidad límite física (82p) │ 1201.2 Kb │ 2002.0 Kb │ 4003.9 Kb │ │",13,10
DB " └───────────────────────────────┴───────────┴───────────┴────────────┴──────┘",13,10
DB " (#) Discos de 360K con formato /DH. (*) No probado. En la lista aparecen",13,10
DB " SOLO los formatos soportados por casi todas las unidades y ordenadores.",13,10
DB 10
DB " Los disquetes 2MGUI utilizan una tecnología totalmente nueva, que permite",13,10
DB " acceder directamente a la unidad, con una técnica ideada por Jesús Arias, sin",13,10
DB " emplear -en la práctica- la controladora de disquetes. En escritura son más",13,10
DB " lentos que un disco normal, pero leyendo lo superan. El consumo de memoria de",13,10
DB " este programa (17 Kb en 1.44M) es elevado. Estos discos son casi tan seguros",13,10
DB " como los 2M normales o los 2MF/M, pero su arquitectura no es la mejor de cara",13,10
DB " a su empleo bajo sistemas multitarea. Funcionan en la mayoría de PC, XT y AT",13,10
DB " con controladora y unidades de alta densidad.",13,10
DB " (2/5) [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " ────────────────── OTRAS OPCIONES DEL PROGRAMA SON ───────────────────",13,10
DB " /Q Hace un formateo rápido de las dos primeras pistas; útil para cambiar",13,10
DB " las características lógicas de un disco no defectuoso ya formateado.",13,10
DB " /L=et Establece la etiqueta de volúmen del disco (máximo 11 caracteres). Se",13,10
DB " admiten mayúsculas y minúsculas.",13,10
DB " /V=et Establece una etiqueta de volúmen incremental en series de discos (es",13,10
DB " preciso que acabe en número).",13,10
DB " /TEST Obtiene con exactitud total la capacidad admitida por la unidad que se",13,10
DB " indique, y determina la velocidad de rotación de la misma. El disco no",13,10
DB " necesita estar formateado y los datos que contuviera se pierden (test",13,10
DB " destructivo). Puede acompañarse de /DD ó /ED para elegir densidad; por",13,10
DB " defecto se realiza el test en alta densidad. También se admite /NODMA.",13,10
DB " /B=n Fuerza el formateo con una determinada capacidad por pista (quizá la",13,10
DB " obtenida por la prueba anterior). Así, se aprovechará totalmente la",13,10
DB " capacidad de una unidad concreta. Estos disquetes podrán ser LEIDOS en",13,10
DB " otras disqueteras, pero su ESCRITURA en unidades peores los dañará.",13,10
DB " /G=n Selecciona el valor del GAP anti-FIFO. La capacidad bruta de la pista",13,10
DB " es la suma de este valor (por defecto, 20) más el indicado con /B: un",13,10
DB " menor GAP permite aumentar /B pero disminuye la seguridad.",13,10
DB " /M=n Elige el número de pistas de alta densidad en el formato /DH (28 por",13,10
DB " defecto, equivalentes a la primera tercera parte del disco).",13,10
DB " /DRON Activa el soporte para DISKCOPY inverso (lo contrario es /DROFF). Use",13,10
DB " solo /DRON o /DROFF si DISKCOPY recalibrara en cada pista. /DRON está",13,10
DB " activo por defecto en DR-DOS 6 y Novell DOS 7.",13,10
DB " (3/5) [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " /DWOFF Desactiva la caché de escritura retardada (lo contrario es /DWON). Por",13,10
DB " defecto, la escritura retardada está activa. Inhíbala si detecta algún",13,10
DB " conflicto con otro software de sistema, si bien sería muy raro. Copiar",13,10
DB " discos (DISKCOPY) sin escritura retardada puede representar horas.",13,10
DB " /X=n Valor para desplazar el comienzo físico de una pista respecto a la que",13,10
DB " le precede, al conmutar de cabezal, expresado en grados (0-359°) de",13,10
DB " longitud angular de la pista (sector sliding /X), por defecto 55°.",13,10
DB " /Y=n Similar al anterior pero al conmutar de cilindro, por defecto 90°. No",13,10
DB " altere /X ni /Y si no conoce su significado: incide en el rendimiento.",13,10
DB " /NODMA Desactiva el funcionamiento en modo DMA. En modo DMA, QEMM necesita el",13,10
DB " parámetro DMA=13 (1.44M) ó DMA=25 (2.88M), aunque EMM386 no. Se puede",13,10
DB " evitar esto (o el cruce de una frontera de DMA) indicando esta opción:",13,10
DB " 2MGUI permite operar en los AT sin DMA, aunque así es menos compatible",13,10
DB " con ciertas configuraciones (cuando funciona, la seguridad es total).",13,10
DB " /EMS Sólo admitido junto a /NODMA, utiliza EMS para consumir sólo 5 Kb.",13,10
DB 10
DB " Derechos de copia:",13,10
DB " ──────────────────",13,10
DB " La tecnología empleada por 2MGUI y el formato de disco resultante son dominio",13,10
DB " público. Cualquier patente posterior de la técnica de acceso a pistas físicas",13,10
DB " completas, realizada en cualquier país, carecerá de validez. Este programa,",13,10
DB " sin embargo, sí es Copyright (C) de su autor. Puede ser libre y gratuitamente",13,10
DB " distribuído; la condición de registro es la del paquete 2M (enviar la tarjeta",13,10
DB " postal al autor).",13,10
DB " (4/5) [PULSA UNA TECLA]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " Ultimas consideraciones:",13,10
DB " ────────────────────────",13,10
DB " - Se puede ejecutar DISKCOPY sobre una unidad 2MGUI, sobre cualquier tipo de",13,10
DB " disco, siempre que el disco destino esté ya formateado, y tenga exactamente",13,10
DB " las mismas características físicas y tamaño que el origen. El DISKCOPY del",13,10
DB " MS-DOS (no del DR-DOS) falla en la primera ejecución sobre un nuevo disco",13,10
DB " cuando no es del mismo tipo que el accedido por última vez; esto es porque",13,10
DB " no soporta que un controlador de dispositivo modifique, dinámicamente, sus",13,10
DB " características físicas. Si DISKCOPY da error, vuelva a ejecutarlo; en todo",13,10
DB " caso, es mejor hacer antes un DIR sobre la unidad, para evitar problemas.",13,10
DB 10
DB " - 2MGUI realiza una escritura retardada (sólo en discos 2MGUI). El usuario no",13,10
DB " debería retirar el disco, aunque haya aparecido ya el prompt del sistema,",13,10
DB " hasta que haya transcurrido algo más de medio segundo.",13,10
DB 10
DB " Importante:",13,10
DB " ───────────",13,10
DB " - Bajo Windows 3 las operaciones sobre disquetes 2MGUI en el administrador de",13,10
DB " archivos dejan colapsado el sistema. Sin embargo, aunque el puntero del",13,10
DB " ratón no obedezca y el teclado parezca estar bloqueado, el sistema no está",13,10
DB " necesariamente colgado. Espere unos segundos antes de resetear. Windows 95",13,10
DB " es compatible con 2MGUI sólo en las sesiones de auténtico MS-DOS.",13,10
DB " - Es conveniente indicar BUFFERS=40 en CONFIG.SYS para mayor rendimiento.",13,10
DB 255
DB 13,10,10
DB " 2M GUINNESS 1.0 - DIRECT DISK DRIVE ACCESS BYPASSING CONTROLLER",13,10
DB " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
DB " C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10
DB 10
DB " 2MGUI [U:] [/DD] [/DH] [/ED] [/T:n] [/R:n] [/C:n] [/S:n] [/F:n] [/N] [/K]",13,10
DB 10
DB " This program gets *all* disk's size available before format process; it is",13,10
DB " also capable of fitting itself at disk drive speed in order to get more size.",13,10
DB 10
DB " You must load it first in CONFIG.SYS with a line like «DEVICE=2MGUI.EXE»;",13,10
DB " from this moment, there will appear as many new disk drive letters as high",13,10
DB " density drives installed on the system. New disks formatted by this program",13,10
DB " only can be used on such new drives, which also support standard disks (and",13,10
DB " even 2M disks if 2M is loaded). In fact, 2MGUI lets OS/2 support 2M disks in",13,10
DB " these new drives. When changing from a new drive to the physical one or vice",13,10
DB " versa, a disk change is simulated (user won't be asked for new disk).",13,10
DB 10
DB " To format new disks, you can execute 2MGUI useing the drive which supports",13,10
DB " them. By default, high density is used; /DD selects double density, /DH makes",13,10
DB " 1/3 in high density and 2/3 in double density (only 360K disks) and /ED means",13,10
DB " 2.88M format; /T selects the number of tracks (80-86, 82 by default), /R the",13,10
DB " minimum number of root files (1-240); /C the cluster size (128-16384) and /S",13,10
DB " the sector size (128-512), both must be a power of 2; /F the FATs (1-2), /N",13,10
DB " turns verify off and /K skips keyboard pauses.",13,10
DB " (1/5) [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " ┌───────────┬───────────┬────────────┐",13,10
DB " │ Double │ High │ Extra high │",13,10
DB " ┌───────────────────────────────┼───────────┼───────────┼────────────┼──────┐",13,10
DB " │ Absolute record before 2M │ 820.0 Kb │ 1394.0 Kb │ -- │ │",13,10
DB " │ Maximum 2M capacity (2MF /M) │ 902.0 Kb │ 1558.0 Kb │ -- │ 5.25 │",13,10
DB " │ Minimum 2MGUI capacity │ 976.7 Kb │ 1639.8 Kb │ 1203.1 Kb# │ (5¼) │",13,10
DB " │ Physical limit (82 tracks) │ 1001.0 Kb │ 1668.2 Kb │ 1228.8 Kb# │ │",13,10
DB " ├───────────────────────────────┼───────────┼───────────┼────────────┼──────┤",13,10
DB " │ Absolute record before 2M │ 984.0 Kb │ 1722.0 Kb │ 2880.0 Kb │ │",13,10
DB " │ Maximum 2M capacity (2MF /M) │ 1066.0 Kb │ 1886.0 Kb │ 3772.0 Kb* │ 3.5 │",13,10
DB " │ Minimum 2MGUI capacity │ 1176.0 Kb │ 1972.0 Kb │ 3944.0 Kb* │ (3½) │",13,10
DB " │ Physical limit (82 tracks) │ 1201.2 Kb │ 2002.0 Kb │ 4003.9 Kb │ │",13,10
DB " └───────────────────────────────┴───────────┴───────────┴────────────┴──────┘",13,10
DB " (#) 360K diskettes with /DH format. (*) Not tested. Here are listed ONLY",13,10
DB " those disk formats supported by most diskette drives and computer systems.",13,10
DB 10
DB " 2MGUI disks use a completely new technology to access a diskette drive",13,10
DB " directly, with a technique discovered by Jesús Arias, bypasing in fact the",13,10
DB " diskette drive controller. Writing is a little slower than a normal disk but",13,10
DB " reading is faster. The memory spent by 2MGUI (usually, 17Kb in 1.44M) is a",13,10
DB " little high. These disks are almost as reliable as 2M normal disks or 2MF/M",13,10
DB " ones, but their design is not as suitable for use in real multitasking",13,10
DB " environs. These diskette formats work on most PC, XT or AT computers with",13,10
DB " high density drives and disk controllers.",13,10
DB " (2/5) [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " ──────────────────── OTHER SWITCHES SUPPORTED ARE ────────────────────",13,10
DB " /Q Performs a quick format of two first tracks. Useful to change logical",13,10
DB " characteristics of a full non-defective already 2mgui-formatted disk.",13,10
DB " /L=lb Sets the volume label of the disk (maximum of 11 characters). It will",13,10
DB " be accepted in either uppercase and lowercase.",13,10
DB " /V=lb Sets an automatic sequencing of labels (the specified one must be",13,10
DB " number terminated).",13,10
DB " /TEST Evals, with high accuracy, the disk capacity supported by the selected",13,10
DB " disk drive, and also measures the drive rotation speed. The test disk",13,10
DB " doesn't need to be formatted and data stored will be lost (destructive",13,10
DB " test). It can be used with /DD or /ED switches to select disk density;",13,10
DB " by default, high density will be used. Also /NODMA can be selected.",13,10
DB " /B=n Forzes a new track size (perhaps the maximum track size reported by",13,10
DB " the previous disk test). So, you can employ all disk capacity of your",13,10
DB " own drive. These disks can be READ without problem on any other disk",13,10
DB " drives, but WRITING them in poorer drives will damage data stored.",13,10
DB " /G=n Selects the anti-FIFO gap value. The crude track size is the addition",13,10
DB " of this value (by default, 20) and the size set with /B: a smaller GAP",13,10
DB " lets you to increment /B but decreases disk reliability.",13,10
DB " /M=n Sets the number of high density tracks in /DH format (by default, 28;",13,10
DB " which means the first third part of the disk).",13,10
DB " /DRON Turns on inverse DISKCOPY support (the opposite is /DROFF). Only must",13,10
DB " be used /DRON or /DROFF if DISKCOPY recalibrates on each track. /DRON",13,10
DB " is set by default in DR-DOS 6 and Novell DOS 7.",13,10
DB " (3/5) [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " /DWOFF Disables delayed-write cache (the opposite is /DWON). By default, the",13,10
DB " delayed write is active. You can turn it off if you detect a conflict",13,10
DB " with any other system software, but this is really unusual. To copy",13,10
DB " disks (DISKCOPY) without delayed write may take hours.",13,10
DB " /X=n Value to shift the beginning of a track from the previous one, when",13,10
DB " changing the head selected shown in degrees (0-359°) of angular length",13,10
DB " of the track (sector sliding /X), 55° by default.",13,10
DB " /Y=n Similar to previous switch, but when changing the cylinder (90°). Do",13,10
DB " not modify /X or /Y without knowing how: they alter disk performance.",13,10
DB " /NODMA Turns off DMA mode. In DMA mode, QEMM needs a DMA=13 (1.44M) or DMA=25",13,10
DB " (2.88M) switch, but EMM386 does not need it. You can avoid this (or a",13,10
DB " DMA frontier crossing problem) with this option: 2MGUI can work in AT",13,10
DB " systems without using DMA; but in this way, it is less compatible with",13,10
DB " some system configurations (but if works, the reliability is similar).",13,10
DB " /EMS Only allowed with /NODMA, saves memory (uses 5 Kb) using EMS instead.",13,10
DB 10
DB " Copyright:",13,10
DB " ──────────",13,10
DB " The technology used by 2MGUI and the resulting disk format are, both, public",13,10
DB " domain. Any patent registered in any country with the technique of access to",13,10
DB " complete tracks will be void. This program, however, is Copyright (C) of its",13,10
DB " author. It can be freely and without charge distributed; the condition to be",13,10
DB " a registered user is the same that with 2M package (to send a postcard to the",13,10
DB " author).",13,10
DB " (4/5) [PRESS ANY KEY]",1
DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8," ",13,10,10
DB " Some finally notes:",13,10
DB " ───────────────────",13,10
DB " - It is possible to run DISKCOPY into a 2MGUI drive, over any one disk format",13,10
DB " available, but target diskette must be already formatted, and must be of",13,10
DB " the same physical characteristics and size as source one. MS-DOS DISKCOPY",13,10
DB " (not DR-DOS one) fails on first execution over a new disk, when it is not",13,10
DB " of the same type as the latest accessed the last time; the problem occurs",13,10
DB " because DISKCOPY doesn't support that a device drive modifies, on the fly,",13,10
DB " it physical characteristics. If DISKCOPY returns an error execute it again;",13,10
DB " but it's preferable to perform a DIR command over the drive before copying.",13,10
DB 10
DB " - 2MGUI performs a delayed-write on diskette drives (speeding up only 2MGUI",13,10
DB " diskettes). The user must not extract the disk although system prompt has",13,10
DB " already returned, until after at least a half second and a little more.",13,10
DB 10
DB " Important:",13,10
DB " ──────────",13,10
DB " - Under Windows 3, operations performed on 2MGUI disks under file manager may",13,10
DB " appear to hang the system. However, although mouse pointer does not answer",13,10
DB " and keyboard seems to be locked, the system has not necessarily crashed.",13,10
DB " Wait for some seconds before resetting it. Windows 95 is compatible with",13,10
DB " 2MGUI only in true MS-DOS sessions.",13,10
DB " - It is recommended to set BUFFERS=40 in CONFIG.SYS to improve performance.",13,10
DB 0
buffer_aux DB 256 DUP (0) ; buffer para alguna función del DOS/EMS
_PRINCIPAL ENDS
tampila EQU 2048 ; 2 Kb de pila son suficientes
_PILA SEGMENT STACK 'STACK'
DB tampila DUP (?)
_PILA ENDS
END main